CSC/ECE 517 Fall 2017/E17A8. Use a profiler to identify the problems / pages that take some time to load & fix them: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(89 intermediate revisions by 3 users not shown)
Line 1: Line 1:
= Optimization for page loading in Expertiza =
= Optimization for page loading in Expertiza =


== Introduction ==
== '''Introduction''' ==
Expertiza is an online system that is used by students to view/submit assignments and review others' work. Expertiza also provides tools to visualize the scores and gauge the improvements made during the course semester. It also facilitates and monitors team projects. It is targeted at educational and non-profit organizations. The project is funded by the National Software Foundation (NSF), NCSU Learning in a Technology-Rich Environment (LITRE) program, the NCSU Faculty Center for Teaching and Learning, the NCSU STEM Initiative, and the Center for Advanced Computing and Communication.
Expertiza is an online system that is used by students to view/submit assignments and review others' work. Expertiza also provides tools to visualize the scores and gauge the improvements made during the course semester. It also facilitates and monitors team projects. It is targeted at educational and non-profit organizations. The project is funded by the National Software Foundation (NSF), NCSU Learning in a Technology-Rich Environment (LITRE) program, the NCSU Faculty Center for Teaching and Learning, the NCSU STEM Initiative, and the Center for Advanced Computing and Communication.


Expertiza is an open-source project with the source code available as a public repository on GitHub. It is developed using Ruby on Rails and is increasingly becoming robust thanks to the innumerable bugs being fixed by the community. The project has a micro-blog on SourceForge where the developer community report bugs and document updates.
Expertiza is an open-source project with the source code available as a public repository on GitHub. It is developed using Ruby on Rails and is increasingly becoming robust thanks to the innumerable bugs being fixed by the community. The project has a micro-blog on SourceForge where the developer community report bugs and document updates.


== Task Description ==
== '''Project Description''' ==


1) Identifying the Expertiza project pages which takes time to load using Rack-mini-profiler and Flamegraphs.  
1) Identifying the Expertiza pages which take time to load using Rack-mini-profiler and Flamegraphs.
2) Propose  fixes which would improve the Expertiza project
3) Optimizing the view ,models and controllers for few of these corresponding fixes to improve the load time of these pages


== Gems Installed  ==
2) Propose fixes which would improve the Expertiza project.


*rack-mini-profiler :- Middleware that displays speed badge for every html page. Designed to work both in production and in development
3) Optimizing the view, models and controllers for few of these corresponding fixes to improve the load time of these pages.
 
== '''Gems Installed'''  ==
 
*rack-mini-profiler :- Middleware that displays speed badge for every html page. Designed to work both in production and in development.
*flamegraphs :- Flame graphs are a visualization of profiled software, allowing the most frequent code-paths to be identified quickly and accurately.
*flamegraphs :- Flame graphs are a visualization of profiled software, allowing the most frequent code-paths to be identified quickly and accurately.
*stackprof:-A sampling call-stack profiler for ruby 2.1+.Downloaded as a dependency for rack-mini-profiler.
*stackprof :- A sampling call-stack profiler for ruby 2.1+.Downloaded as a dependency for rack-mini-profiler.
*fast_stack :-fast_stack is dynamically resizable data structure optimized for fast iteration over the large arrays of similar elements avoiding memory fragmentation.
*fast_stack :- fast_stack is dynamically resizable data structure optimized for fast iteration over the large arrays of similar elements avoiding memory fragmentation.
*Kaminari :- A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for modern web app frameworks and ORMs.
 
== '''Pages which needs to be optimized''' ==
 
1) expertiza.ncsu.edu/grades/view?id=<ID of the team>
 
2) expertiza.ncsu.edu/users/list
 
== '''Project Design''' ==
 
 
For the purpose of this project, experts in the expertiza domain are Instructors.
 
The following two patterns are implemented in the project -
 
1.MVC Pattern - The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view, and controller, respectively).
 
2.DRY Principle - We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.
 
3.Optimization - In order to optimize, we need to understand the factors which are causing the lag. This can be identified by using the flamegraph generation method and rack-mini-profiler statistics.
 
=='''Approach'''==
To complete the given task, we identified the factors which are causing the lag. This was done by using flamegraph generation and rack-mini-profiler statistics. The statistics generated by rack miniprofiler helped us to understand the time taken by each component to get loaded. From these statistics, we identified the model/controller/view/database query which is causing this latency. From here, we identified the methods which needed to be implemented in order to optimize the webpage rendering.
 
Optimization approach for the pages:
*users/list :- The approach to reduce loading time on this page was by implementing pagination. Instead of displaying all users and their data all at once, we display a certain number of users on one page, and rest of the users can be viewed by accessing the later pages. This reduces loading time of the page by reducing the amount of data to be fetched.
*grades/view : Ajax must be used for the optimization. Currently, all the data for all the teams present is loaded when the webpage is accessed. Instead, data for particular teams can be loaded when the user clicks on the expand button for that particular team. Thus, data for each team should be loaded asynchronously with ajax.
 
== '''Analysis of the pages''' ==
 
===FlameGraph Statistics===
The following is the flamegraph for this page:-
 


[[File:f.png]]


== Pages which needs to be optimized ==
The X axis of the FlameGraph represents the time taken to load the page. It can give a clear picture of where the expertiza page is getting bogged down. The widest layers take the longest to run. They’re the areas one should look into, because speeding them up could have the biggest impact. As we can see over here, most of the time taken over here is in the controller action.


1) http://localhost:3000/tree_display/list
===MiniProfiler Statistics===


== Approach ==
The following is the rack-mini-profiler statistics for the page:-
Student has the task of performing review of others' work as well as self review. Every team gets their review from peers and at present the composite score is the average of all the review scores that they have received. Added to this score, the self review score is also calculated for each team member, based on its closeness to the peer reviewed score. To implement this, the student needs to review his own work based on the same rubrics used for peer review and only after completion of the self review, their peer review scores will be visible. The composite score is calculated by the sum of the peer review average score and 100 minus the difference between self and peer review score. The self review score is displayed adjacent to the peer review score. As the composite score is based on the individual self reviews, they vary for each member of the team unlike the peer review score which is the same.


=== MVC Pattern ===


Expertiza is developed using the nuances of the MVC Design Architecture where Models, Views and Controllers are coupled to a very low level. The model manages all the data and the logic related to the data. The controller accepts data from the Models and feeds the Views with a favorable form of the data. The view presents the data to the user.
[[File:tre1.png]]


=== Observer Pattern ===


The advantage of using the Observer Pattern is that the object being observed need not worry about any changes in its state. An Observer Class is added whose objects will look into the changes in the state of the Object being observed.  
The box which is seen in the leftmost corner is the MiniProfiler statistics. MiniProfiler gives  a constant notification of how long each page takes to load. The miniprofiler statistics show the time taken to render the view as well as the corresponding SQL calls.


Here, the observers are the reviewers and the assignment is the object being observed. In case of Self-Review, an Observer can be used to tell the system that the reviewer is now open to reviewing the works of his peers.


[[File:Design.jpg]]
[[File:tree2.png]]


[[File:Design2.jpg]]


This image shows the time and the number of SQL calls which are required for each rendering.


== Implementation ==


=== Devising a formula for Self-Review scores ===
[[File:tree5.png]]


Changes made in app/views/grades/_participant.html.erb, app/views/grades/_participant_charts.html.erb and app/views/grades/_participant_title.html.erb.


Here and everywhere else in this document, 'Raw Self-Review' score indicates the score assigned by the participants assessing one's own work. Self-Review score is a metric used to measure the extent of agreement between the Raw Self-Review score and the Average Peer-Review score.
Here as we can see the total number of SQL calls required for children_node_ng is 1123. This is causing the latency in the entire page by 10564.8 ms. These statistics helped us to identify the method which needs to be refactored.


The highlighted portion of the screenshot below shows how the Self-Review score is obtained from the Raw Self-Review score.


[[File:mypic5.jpg]]
[[File:tree6.png]]


=== Graphically representing Self-Review score ===


Changes made in app/views/grades/_participant_charts.html.erb.  
The total number of SQL calls required for 2 components here is 2 each. Hence we do not need to refactor this component.


In accordance with the design paradigm of Expertiza, we developed a chart (or a circle) to represent the Self-Review Score (Again, remember that this is not the Raw Self-Review score. The Raw Self-Review score is of no use to the participants because it was, in fact, their opinion of the work done. The computed Self-Review score, on the other hand, is more useful as it depicts the level of agreement between the opinions of the participant and the reviewers.). We also ensured that the circle is colored similar to the other charts in the page (other than the final score chart, which was deliberately designed to be bright and unique).  
===  Solution ===
*'''users/list'''
The time taken to load the page was high because the server had to access through hundreds of rows in the database .The page was rendering the entire row of database at the same time. Pagination helped to split the database  into manageable chunks of data.


The following screenshot of a code snippet shows the creation of the circle for Self-Review score.
Code added to app/controllers/users_controller.rb
  def list
    user = session[:user]
  @users=Kaminari.paginate_array(user.get_user_list).page(params[:page])
  end


[[File:mypic2.jpg]]
Code added to app/models/user.rb
  <%= paginate @user %>


=== Consolidation of Self-Review score into Final score ===
Code added to app/views/users/list.html.erb
  <%= paginate @users %>


Changes made in app/views/grades/_participant.html.erb, app/views/grades/_participant_charts.html.erb and app/views/grades/_participant_title.html.erb.  
*'''grades/view'''
The grades/view is the page where the instructor accesses the grades statistics of each student.
The reason for the slow down in the page is that the data for all the teams were loaded as soon as the page was loaded.The design of the page has an individual tab for each team, hence loading the entire data as soon as the page is loaded is quite redundant as the instructor needs to access the scores of each individual team at a given time.
The solution to this problem is to access the individual team statistics from the database when the instructor clicks the tab specified for the particular individual.
The existing code consists of a for loop in views/grades/_teams.html.erb, which renders the partial "views/grades/_tabbing.html.erb" which displays the data repeatedly. Instead, this partial could be rendered through AJAX or JQuery, whenever the expand button is clicked. This would save redundant loading of data and thus reduce the loading time of the page.


Self-Review score cannot be a major part of the Final score. On the other hand, the Peer-Review scores must be the dominant component of Final score. After consulting with the Professor, we decided to give a 10% weightage to the Self-Review score and a 90% weightage to the Peer-Review score. We also deliberately made this non-configurable in the future because it is not to be meddled with; a small mistake in coding can lead to repercussions in different controllers that is undesirable.
'''Issues faced during implementation of this solution''':-  


The highlighted portion of the following screenshot shows the composition of the Final score.
*While implementing this fix, we first created a controller method, which would render the required partial "views/grades/_tabbing.html.erb" when called.We also created a route for this controller method.
*We passed the required data through the Rails params hash. However, since one argument that needed to be passed (tscore) is a Hash, when it enters the params hash, it is getting converted to a String.
*We tried passing the hash as it is, but after doing this all the data in the hash is not retained, i.e. there is a loss of data.
*We also tried converting the String back into Hash by using the eval method, and to_unsafe_h method.
*However, these methods require the hash to be present in a normal form i.e. key value pairs.
*But our hash has values as Objects, thus these methods cannot be applied
*Thus, we are unable to access the data in the String-hash.
*If this could be done, then our approach would result in successfully decreasing the loading time of the webpage.


[[File:mypic3.jpg]]
=='''Test Plan'''==
The project is based on optimizing the time required to load the pages which has been mentioned above,in order to test that there is an improvement in the time taken to load these pages one will have to compare the initial loading time and the time taken after the code has been modified.


=== Ensuring Self-Review is done before Viewing scores ===
===Initial Setup for testing===


Changes made in app/views/student_task/view.html.erb.
1)Clone the git repository.


One sensible requirement of the project was to ensure every participant of an assignment evaluates one's own work before looking into the scores assigned by others. This is done to avoid an explicit or implicit comparison of the raw self-review score to the peer-review scores.
2)Go to the commit on 3rd November (name: initial setup), this is the code which is originally provided by the professor and has not been modified. It however consists of the two gems required to check the loading time.


By ensuring that every participant performs the self-review before looking into the scores assigned to his/her work, we also ensure that the raw self-review score is an honest indication of what the participant thinks about one's own work.
3)To login as instructor :-
Username :- instructor6
Password :- password


In the screenshot below, the 'if' and 'else' statements ensure the same.
===Testing===


[[File:mypic4.jpg]]
Check the time taken to load the page localhost:3000/tree_display/list on the left corner and compare the same for the latest pull. You will notice a substantial reduction in the loading time.


== Testing ==
===Automated Test===


Kindly check the Screencast video.
There can be no automated test for this program since the improvement in the performance is due to the inclusion of the pagination gem.  


# Juxtaposing Peer and Self-Review Scores - From the Assignment Home Page, click on 'Your Scores' to view both Average Peer-Review, Self-Review and Final Scores.
Hence testing if the pagination gem will work is equivalent to checking if rails is working.  
# Combine Self and Peer-Reviews into a Composite Score - From the Assignment Home Page, click on 'Your Scores' to view the Composite Score assigned to you based on the closeness of your Self-Review score with the Average Peer-Review Score.
# Complete Self-Review before checking Peer-Review Scores - From the Assignment Home Page, click on 'Others' Work' to try to submit Peer-Reviews for the projects submitted by others. However, this should be forbidden unless you have submitted a Self-Review of your project.


== Scope for Future Work ==
As testing rails is not recommended no automated test is added for changes made.


*The words used in the self-reviews can be used to judge the seriousness of the reviews.
=== Links ===
*The changes in the scores of the self-reviews can be used to judge whether teams have worked to their own expectations.
* Project Demo : https://www.youtube.com/watch?v=qQi6yqbmST4&t=4s
*In order to establish a common standard in the reviewing system, the absolute change in the review scores can be used to judge an individual.
* Project Repository: https://github.com/sahildorwat/expertiza
* Pull request: https://github.com/expertiza/expertiza/pull/1122
* Github issue: https://github.com/expertiza/expertiza/issues/1121

Latest revision as of 03:32, 17 December 2017

Optimization for page loading in Expertiza

Introduction

Expertiza is an online system that is used by students to view/submit assignments and review others' work. Expertiza also provides tools to visualize the scores and gauge the improvements made during the course semester. It also facilitates and monitors team projects. It is targeted at educational and non-profit organizations. The project is funded by the National Software Foundation (NSF), NCSU Learning in a Technology-Rich Environment (LITRE) program, the NCSU Faculty Center for Teaching and Learning, the NCSU STEM Initiative, and the Center for Advanced Computing and Communication.

Expertiza is an open-source project with the source code available as a public repository on GitHub. It is developed using Ruby on Rails and is increasingly becoming robust thanks to the innumerable bugs being fixed by the community. The project has a micro-blog on SourceForge where the developer community report bugs and document updates.

Project Description

1) Identifying the Expertiza pages which take time to load using Rack-mini-profiler and Flamegraphs.

2) Propose fixes which would improve the Expertiza project.

3) Optimizing the view, models and controllers for few of these corresponding fixes to improve the load time of these pages.

Gems Installed

  • rack-mini-profiler :- Middleware that displays speed badge for every html page. Designed to work both in production and in development.
  • flamegraphs :- Flame graphs are a visualization of profiled software, allowing the most frequent code-paths to be identified quickly and accurately.
  • stackprof :- A sampling call-stack profiler for ruby 2.1+.Downloaded as a dependency for rack-mini-profiler.
  • fast_stack :- fast_stack is dynamically resizable data structure optimized for fast iteration over the large arrays of similar elements avoiding memory fragmentation.
  • Kaminari :- A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for modern web app frameworks and ORMs.

Pages which needs to be optimized

1) expertiza.ncsu.edu/grades/view?id=<ID of the team>

2) expertiza.ncsu.edu/users/list

Project Design

For the purpose of this project, experts in the expertiza domain are Instructors.

The following two patterns are implemented in the project -

1.MVC Pattern - The project is implemented in Ruby on Rails that uses MVC architecture. It separates an application’s data model, user interface, and control logic into three distinct components (model, view, and controller, respectively).

2.DRY Principle - We are trying to reuse the existing functionalities in Expertiza, thus avoiding code duplication. Whenever possible, code modification based on the existing classes, controllers, or tables will be done instead of creating the new one.

3.Optimization - In order to optimize, we need to understand the factors which are causing the lag. This can be identified by using the flamegraph generation method and rack-mini-profiler statistics.

Approach

To complete the given task, we identified the factors which are causing the lag. This was done by using flamegraph generation and rack-mini-profiler statistics. The statistics generated by rack miniprofiler helped us to understand the time taken by each component to get loaded. From these statistics, we identified the model/controller/view/database query which is causing this latency. From here, we identified the methods which needed to be implemented in order to optimize the webpage rendering.

Optimization approach for the pages:

  • users/list :- The approach to reduce loading time on this page was by implementing pagination. Instead of displaying all users and their data all at once, we display a certain number of users on one page, and rest of the users can be viewed by accessing the later pages. This reduces loading time of the page by reducing the amount of data to be fetched.
  • grades/view : Ajax must be used for the optimization. Currently, all the data for all the teams present is loaded when the webpage is accessed. Instead, data for particular teams can be loaded when the user clicks on the expand button for that particular team. Thus, data for each team should be loaded asynchronously with ajax.

Analysis of the pages

FlameGraph Statistics

The following is the flamegraph for this page:-


The X axis of the FlameGraph represents the time taken to load the page. It can give a clear picture of where the expertiza page is getting bogged down. The widest layers take the longest to run. They’re the areas one should look into, because speeding them up could have the biggest impact. As we can see over here, most of the time taken over here is in the controller action.

MiniProfiler Statistics

The following is the rack-mini-profiler statistics for the page:-



The box which is seen in the leftmost corner is the MiniProfiler statistics. MiniProfiler gives a constant notification of how long each page takes to load. The miniprofiler statistics show the time taken to render the view as well as the corresponding SQL calls.



This image shows the time and the number of SQL calls which are required for each rendering.



Here as we can see the total number of SQL calls required for children_node_ng is 1123. This is causing the latency in the entire page by 10564.8 ms. These statistics helped us to identify the method which needs to be refactored.



The total number of SQL calls required for 2 components here is 2 each. Hence we do not need to refactor this component.

Solution

  • users/list

The time taken to load the page was high because the server had to access through hundreds of rows in the database .The page was rendering the entire row of database at the same time. Pagination helped to split the database into manageable chunks of data.

Code added to app/controllers/users_controller.rb

 def list
   user = session[:user]
 	@users=Kaminari.paginate_array(user.get_user_list).page(params[:page])
 end

Code added to app/models/user.rb

 <%= paginate @user %>

Code added to app/views/users/list.html.erb

 <%= paginate @users %>
  • grades/view

The grades/view is the page where the instructor accesses the grades statistics of each student. The reason for the slow down in the page is that the data for all the teams were loaded as soon as the page was loaded.The design of the page has an individual tab for each team, hence loading the entire data as soon as the page is loaded is quite redundant as the instructor needs to access the scores of each individual team at a given time. The solution to this problem is to access the individual team statistics from the database when the instructor clicks the tab specified for the particular individual. The existing code consists of a for loop in views/grades/_teams.html.erb, which renders the partial "views/grades/_tabbing.html.erb" which displays the data repeatedly. Instead, this partial could be rendered through AJAX or JQuery, whenever the expand button is clicked. This would save redundant loading of data and thus reduce the loading time of the page.

Issues faced during implementation of this solution:-

  • While implementing this fix, we first created a controller method, which would render the required partial "views/grades/_tabbing.html.erb" when called.We also created a route for this controller method.
  • We passed the required data through the Rails params hash. However, since one argument that needed to be passed (tscore) is a Hash, when it enters the params hash, it is getting converted to a String.
  • We tried passing the hash as it is, but after doing this all the data in the hash is not retained, i.e. there is a loss of data.
  • We also tried converting the String back into Hash by using the eval method, and to_unsafe_h method.
  • However, these methods require the hash to be present in a normal form i.e. key value pairs.
  • But our hash has values as Objects, thus these methods cannot be applied
  • Thus, we are unable to access the data in the String-hash.
  • If this could be done, then our approach would result in successfully decreasing the loading time of the webpage.

Test Plan

The project is based on optimizing the time required to load the pages which has been mentioned above,in order to test that there is an improvement in the time taken to load these pages one will have to compare the initial loading time and the time taken after the code has been modified.

Initial Setup for testing

1)Clone the git repository.

2)Go to the commit on 3rd November (name: initial setup), this is the code which is originally provided by the professor and has not been modified. It however consists of the two gems required to check the loading time.

3)To login as instructor :- Username :- instructor6 Password :- password

Testing

Check the time taken to load the page localhost:3000/tree_display/list on the left corner and compare the same for the latest pull. You will notice a substantial reduction in the loading time.

Automated Test

There can be no automated test for this program since the improvement in the performance is due to the inclusion of the pagination gem.

Hence testing if the pagination gem will work is equivalent to checking if rails is working.

As testing rails is not recommended no automated test is added for changes made.

Links