-
- Organizations involved and roles
-
-
- Understanding the code base
- Application architecture
- Domain objects
- Other design topics
By activating the performance probes and sending reports, everyone can help to improve Sigmah. Reports contains informations about the time spent while doing common tasks like opening a project.
If a functionality feels slow, send us your report to help us understand what takes time and how we can fix it.
Performance measurement is a new user authorisation. It is deactivated by default and should be added to the user profiles by an administrator.
If you own the Manage users
authorisation, you can allow or disallow users to measure performance by doing the following steps:
Users
tab of the Administration.edit
button next to the user profile to authorize or deauthorize.Others
section of the Global Authorizations
.Probes management
authorization to allow or disallow the measurement of performances.
When a user has the right to activate and deactivate probes, a new icon will appear for him at the top of the screen. Hover your mouse cursor over it to display the probes management menu
and select Enable trace mode
to activate measurement.
When active, the probes management
icon will turn white:
At this point, Sigmah will measure the time taken when doing common tasks. These data are saved locally and won't be sent without your consent.
To send a report, simply go to the probe management menu
and click on the Send report
button.
The reports will be sent to you and to the Sigmah development team. To configure who can receive reports, see the configuration section.
The mail sent will include 2 files:
When contributing to Sigmah, you can measure the impact of your developments by frequently running the automated tests. By comparing the generated reports, you will be able to see how your changes affected the performances of Sigmah.
The automated tests are using Selenium to simulate a user browsing Sigmah. For more information about Selenium, you can visit Selenium home page.
You can run the automated tests on your computer or use the pre-configured virtual machine available on sigmah.org.
If you choose to use the virtual machine, you can skip the installation and configuration phase.
Selenium require Firefox to run.
From Firefox, visit the add-on installation page of Selenium IDE. Click on Add to Firefox
to install Selenium:
Download this user-extension.js file.
Open Selenium IDE preferences and select the file you just downloaded into the Selenium Core Extensions
field:
You are now ready to run the automated tests.
Open Firefox. In the menubar, select Tools
then Selenium IDE
to open Selenium.
Copy the following script in the Source
tab of Selenium and edit the following values:
https://optimisation.sigmah.org/#login
by the URL of your instance of Sigmah.user@sigmah.org
by the login of the user to use.yourpassword
by the password to use.index < 10;
(note: <
means less than
).
When you are done, switch to the table
tab and hit play
to let Selenium execute the tests.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://selenium-ide.openqa.org/profiles/test-case"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="selenium.base" href="https://optimisation.sigmah.org/#login" /> <title>Boucle-10-ID</title> </head> <body> <table cellpadding="1" cellspacing="1" border="1"> <thead> <tr><td rowspan="1" colspan="3">Boucle-10-ID</td></tr> </thead><tbody> <!-- Identification --> <tr> <td>open</td> <td>/#login</td> <td></td> </tr> <tr> <td>type</td> <td>id=loginEmailId</td> <td>user@sigmah.org</td> </tr> <tr> <td>type</td> <td>id=loginPasswordId</td> <td>yourpassword</td> </tr> <tr> <td>clickAndWait</td> <td>css=button.x-btn-text</td> <td></td> </tr> <!-- Activation trace --> <tr> <td>click</td> <td>id=activeDesactiveButtonId</td> <td></td> </tr> <!-- Début de boucle --> <tr> <td>getEval</td> <td>index = 0;</td> <td></td> </tr> <tr> <td>while</td> <td>index < 10;</td> <td></td> </tr> <tr> <td>storeEval</td> <td>index</td> <td>value</td> </tr> <tr> <td>echo</td> <td>${value}</td> <td></td> </tr> <!-- Ouverture projet --> <tr> <td>click</td> <td>id=projectCodeColumnId_-45917</td> <td></td> </tr> <!-- Ouverture agenda --> <tr> <td>click</td> <td>id=agendaSubMenuId</td> <td></td> </tr> <!-- Fermeture projet--> <tr> <td>selectWindow</td> <td>null</td> <td></td> </tr> <tr> <td>click</td> <td>id=dashboardProjectTabId5917</td> <td></td> </tr> <tr> <td>getEval</td> <td>index++;</td> <td></td> </tr> <!-- Fin de boucle --> <tr> <td>endWhile</td> <td></td> <td></td> </tr> <!-- Désactivation trace--> <tr> <td>click</td> <td>id=activeDesactiveButtonId</td> <td></td> </tr> <!-- Envoi du rapport --> <tr> <td>click</td> <td>id=sendReportButtonId</td> <td></td> </tr> <!-- Fin d'identification --> <tr> <td>click</td> <td>link=Fermer session</td> <td></td> </tr> <tr> <td>click</td> <td>//table[@id='yesButtonId']/tbody/tr[2]/td[2]/em/button</td> <td></td> </tr> </tbody></table> </body> </html>
You can record your own test by clicking on the record
button in the Selenium IDE window.
See Selenium help page for more information.
Scenario
enumeration.Profiler
to define the start and end points of your Scenario
See the Probe API section for more information about the code required.
When running a Scenario
, the start time, duration of every checkpoint is saved in IndexedDB. The raw report is a JSON export of the entire database.
Each entry is the result of an execution of a scenario. For each execution, the following fields are saved:
applicationCacheStatus
: the state of ApplicationCache. You should ignore execution results when the state is not IDLE
. Performances are badly hurt when ApplicationCache is working. Hopefully, this only happen once every new version update.checkpoints
: Name, start time and duration of each checkpoint.date
: Start date of the execution.duration
: Total duration of the execution.id
: Execution identifier in the local database. Can be safely ignored.online
: Tells if the user was online or offline when the execution started. Offline mode is usually faster so you should avoid mixing the results of online and offline mode.scenario
: Name of the executed scenario.userAgent
: User-agent of the web browser used.versionNumber
: Version of Sigmah used.
Inside of the sigmah.properties
, locate the mail.optimisation
entries. They define what will be sent by email and who will receive the reports:
mail.optimisation.to.address=osarrat@urd.org mail.optimisation.copy.address= mail.optimisation.markdownfile.name=sigmah_performance_report.md mail.optimisation.jsonfile.name=sigmah_performance_raw_values.json
mail.optimisation.to.address
and mail.optimisation.copy.address
are email addresses fields. You can define multiple addresses by separating them with a semicolon (';'). All of theses addresses will receive every reports sent by users. If you want the Sigmah team to receive your reports you should ensure that osarrat@urd.org
is present in one of those two fields.mail.optimisation.markdownfile.name
is the name of the main report. It is a plain-text file following the Markdown syntax.mail.optimisation.jsonfile.name
is the name of the raw report. It is a json file and is not intended to be understood as is. It contains the raw value measured by the probes. If you are a developer and are interested in understanding this file, see the Understanding the raw report section.You can edit this file will Sigmah is running. The changes will be taken right away, no reboot of the server is required.
Currently Sigmah records the duration of the following actions:
The probe API is located in the org.sigmah.client.util.profiler
.
Here is a quick list of the objects to use:
Throughout this section we will see how to create a scenario named Update Reminder that record the time taken to mark a reminder as done/todo.
Open the Scenario
enum and add a case for your new scenario. To respect the coding conventions, you should name your scenario in all capital cases and replace spaces by underscores.
For our example, we will add a new case named UPDATE_REMINDER to the enum:
public enum Scenario { AGENDA, OPEN_PROJECT, UPDATE_REMINDER; // Our new scenario }
In your code, use the startScenario(Scenario)
method of the Profiler
to start the recording of a new execution of any scenario. Only one execution can be recorded at a time. If an execution is running, starting a new one will lose any unsaved information.
To end the execution and save its data inside the database, use the endScenario(Scenario)
method of the Profiler
.
You can also pause and resume execution with the pauseScenario(Scenario)
and resumeScenario(Scenario)
if your scenario require user interaction to continue. You should avoid recording waits for user interaction to ensure that the recorded time reflect the time spent by Sigmah.
For our example, we will edit the ProjectDashboardPresenter
and start the scenario when the user clicks on the check:
// -- // Reminders / Monitored Points edit update event handlers. // -- view.getRemindersGrid().getStore().addListener(Store.Update, new Listener<StoreEvent<ReminderDTO>>() { @Override public void handleEvent(final StoreEvent<ReminderDTO> event) { // Manages only edit event. if (event.getOperation() == RecordUpdate.EDIT) { // Starting the scenario Profiler.INSTANCE.startScenario(Scenario.UPDATE_REMINDER); onReminderUpdate(event.getModel()); } } });
The end of our scenario happens when the UpdateReminders
command ends with success:
// Updates points. dispatch.execute(new UpdateReminders(edited), new CommandResultHandler<ListResult<ReminderDTO>>() { @Override public void onCommandFailure(final Throwable e) { // ... } @Override public void onCommandSuccess(final ListResult<ReminderDTO> result) { view.getRemindersGrid().getStore().commitChanges(); for (final ReminderDTO point : result.getList()) { point.setIsCompleted(); view.getRemindersGrid().getStore().update(point); } N10N.notification(I18N.CONSTANTS.infoConfirmation(), I18N.CONSTANTS.reminderUpdateConfirm(), MessageType.INFO); // Ending the scenario Profiler.INSTANCE.endScenario(Scenario.UPDATE_REMINDER); }
At this point, you can already try and see the time taken to update a reminder.
You can use the markCheckpoint(Scenario, String)
method of the Profiler
to measure the time taken by a specific code block. Just surround the desired block with 2 checkpoints (usually named “before [function]“ and “after [function]“).
For our example, we will measure the time taken to update the user interface:
@Override public void onCommandSuccess(final ListResult<ReminderDTO> result) { // Before UI update checkpoint Profiler.INSTANCE.markCheckpoint(Scenario.UPDATE_REMINDER, "Before UI update"); view.getRemindersGrid().getStore().commitChanges(); for (final ReminderDTO point : result.getList()) { point.setIsCompleted(); view.getRemindersGrid().getStore().update(point); } // After UI update checkpoint Profiler.INSTANCE.markCheckpoint(Scenario.UPDATE_REMINDER, "After UI update"); N10N.notification(I18N.CONSTANTS.infoConfirmation(), I18N.CONSTANTS.reminderUpdateConfirm(), MessageType.INFO); // Ending the scenario Profiler.INSTANCE.endScenario(Scenario.UPDATE_REMINDER); }