Skip to content

Commit 9f3ec87

Browse files
authored
🧪 Profile live statistics page (#5365)
Adds a sort of profiling to this page by placing some timers in some key function where I think the slowdown happens. Why is it so hacky? I tried for several hours to use werkzeug's `ProfilerMiddleware` but I think there's a bug with the implementation, as several people have reported in some other tools: django-commons/django-debug-toolbar#1875, jazzband/django-silk#682 I thought that since we didn't need the full-fledged tool and didn't want to spend more time on this, this approach would suffice.
1 parent 09ae9e5 commit 9f3ec87

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

website/statistics.py

+23-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@
1414
from website.flask_helpers import render_template
1515
from website import querylog
1616
from website.auth import is_admin, is_teacher, requires_admin, requires_login
17-
17+
from timeit import default_timer as timer
1818
from .database import Database
1919
from .website_module import WebsiteModule, route
2020
from bs4 import BeautifulSoup
2121

22+
import logging
23+
from logging_config import LOGGING_CONFIG
24+
from logging.config import dictConfig as logConfig
25+
26+
logConfig(LOGGING_CONFIG)
27+
logger = logging.getLogger(__name__)
28+
2229
"""The Key tuple is used to aggregate the raw data by level, time or username."""
2330
Key = namedtuple("Key", ["name", "class_"])
2431
level_key = Key("level", int)
@@ -335,8 +342,11 @@ def __init__(self, db: Database):
335342
self.MAX_FEED_SIZE = 4
336343

337344
def __selected_levels(self, class_id):
345+
start = timer()
338346
class_customization = get_customizations(self.db, class_id)
339347
class_overview = class_customization.get('dashboard_customization')
348+
end = timer()
349+
logger.debug(f'Time taken by __selected_levels {end-start}')
340350
if class_overview:
341351
return class_overview.get('selected_levels', [1])
342352
return [1]
@@ -349,6 +359,7 @@ def __common_errors(self, class_id):
349359

350360
def __all_students(self, class_):
351361
"""Returns a list of all students in a class along with some info."""
362+
start = timer()
352363
students = []
353364
for student_username in class_.get("students", []):
354365
programs = self.db.programs_for_user(student_username)
@@ -365,6 +376,8 @@ def __all_students(self, class_):
365376
"current_level": programs[0]['level'] if programs else '0'
366377
}
367378
)
379+
end = timer()
380+
logger.debug(f'Time taken by __all_students {end-start}')
368381
return students
369382

370383
def __get_adventures_for_overview(self, user, class_id):
@@ -440,6 +453,7 @@ def render_live_stats(self, user, class_id):
440453
)
441454

442455
def get_class_live_stats(self, user, class_):
456+
start = timer()
443457
# Retrieve common errors and selected levels in class overview from the database for class
444458
selected_levels = self.__selected_levels(class_['id'])
445459
if selected_levels:
@@ -476,7 +490,8 @@ def get_class_live_stats(self, user, class_):
476490
programs_for_student[_student] = adventures_for_student
477491
if programs_for_student != []:
478492
attempted_adventures[level] = programs_for_student
479-
493+
end = timer()
494+
logger.debug(f'Time taken by get_class_live_stats {end-start}')
480495
return students, common_errors, selected_levels, quiz_info, attempted_adventures, adventures
481496

482497
@route("/live_stats/class/<class_id>/select_level", methods=["GET"])
@@ -810,6 +825,7 @@ def retrieve_exceptions_per_student(self, class_id):
810825
:param class_id: class id
811826
:return: exceptions_per_user
812827
"""
828+
start = timer()
813829
class_ = self.db.get_class(class_id)
814830
exceptions_per_user = {}
815831
students = sorted(class_.get("students", []))
@@ -820,7 +836,8 @@ def retrieve_exceptions_per_student(self, class_id):
820836
program_stats = program_stats[-1]
821837
exceptions = {k: v for k, v in program_stats.items() if k.lower().endswith("exception")}
822838
exceptions_per_user[student_username] = exceptions
823-
839+
end = timer()
840+
logger.debug(f'Tike taken by retrieve_exceptions_per_student {end-start}')
824841
return exceptions_per_user
825842

826843
def new_id_calc(self, common_errors, class_id):
@@ -856,6 +873,7 @@ def common_exception_detection(self, class_id, user):
856873
"""
857874
Detects misconceptions of students in the class based on errors they are making.
858875
"""
876+
start = timer()
859877
common_errors = self.__common_errors(class_id)
860878
# Group the error messages by session and count their occurrences
861879
exceptions_per_user = self.retrieve_exceptions_per_student(class_id) # retrieves relevant data from db
@@ -913,7 +931,8 @@ def common_exception_detection(self, class_id, user):
913931
'active': 1,
914932
"students": users_only
915933
})
916-
934+
end = timer()
935+
logger.debug(f'Time taken by common_exception_detection {end-start}')
917936
return self.db.update_class_errors(common_errors)
918937

919938
@route("/live_stats/class/<class_id>", methods=["POST"])

0 commit comments

Comments
 (0)