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 ScenarioSee 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);
}