Skip to content
petrs edited this page Jul 27, 2017 · 4 revisions

Performance profiler

The performance profiling parts of Java Card applet code is a notoriously difficult task. As the card environment is build to protect stored and processed secrets even against an attacker with direct physical access, it's difficult to obtain precise timing trace for the executed code. We are not aware of any free performance profiler for Java Card platform so we decided to build one.

  1. A developer is required to manually insert several performance “traps” (cut&paste fixed strings) into a part of source code of developer's interest.
PM.check(PMC.TRAP_methodName_0); 
// some code to measure
PM.check(PMC.TRAP_methodName_0); 
// another code to measure
PM.check(PMC.TRAP_methodName_0); 

All modified files must be copied into directory input_applet_files inside following directory structure:

baseDir
  --> templates 
      --> input_applet_files          <--- copy your files with template traps here
      --> template_profiler_applet    // don't touch
      --> template_profiler_client    // don't touch
  --> target // automatically generated, will contain generated profiler files and later also annotated measured performance
      --> profiler_applet             // resulting card-side files
          --> perf                    // parent directory for separate profiling sessions
              --> 1501161963998       // example directory with profiling results   
              ...
      --> profiler_client             // resulting personalized client-side profiler
  1. JCProfiler.jar tool is executed with parameter --setTraps against a source code with previously inserted generic traps. As a result, generic traps are personalized, necessary on-card classes and constants are generated and complete client-side testing application is automatically created.
// Run
java -jar JCProfiler.jar --setTraps --baseDir demo --methodBaseName methodName --trapIDStartConst 7770
PM.check(PMC.TRAP_methodName_1); 
// some code to measure
PM.check(PMC.TRAP_methodName_2); 
// another code to measure
PM.check(PMC.TRAP_methodName_3); 
...
public class PMC {
...
  public static final short TRAP_methodName_1 = (short) 0x7781; 
...
}
  1. A developer provides applet AID and APDU command(s) which will trigger the visit to measured code (now including performance traps).
// Define valid APDU to trigger target on-card operation 
static final byte[] APDU_TRIGGER = {0xB0, 0x40, 0, 0, 0};
  1. Target card is converted and loaded with applet with personalized performance traps using suitable tool, e.g., GlobalPlatformPro
  2. Client-side testing application is executed. The target operation is executed multiple times, but with different performance trap ID set. As a result, on-card operation is prematurely interrupted on the specified performance trap. The corresponding client-side measurements are collected and processed to compute time difference between consequtive traps.
...
ECPoint_multiplication_x: TRAP_ECPOINT_MULT_X_1, 40
ECPoint_multiplication_x: TRAP_ECPOINT_MULT_X_2, 52
ECPoint_multiplication_x: TRAP_ECPOINT_MULT_X_3, 172
ECPoint_multiplication_x: TRAP_ECPOINT_MULT_X_4, 181
ECPoint_multiplication_x: TRAP_ECPOINT_MULT_X_5, 367
...
  1. The original source code is annotated with computed timing difference, card name and unique session for every reached trap (see example below).
private short multiplication_x_KA(Bignat scalar, byte[] outBuffer, short outBufferOffset) {
  PM.check(PMC.TRAP_ECPOINT_MULT_X_1); // 40 ms (gd60,1500968219581) 
  priv.setS(scalar.as_byte_array(), (short) 0, scalar.length());
  PM.check(PMC.TRAP_ECPOINT_MULT_X_2); // 12 ms (gd60,1500968219581) 

  keyAgreement.init(priv);
  PM.check(PMC.TRAP_ECPOINT_MULT_X_3); // 120 ms (gd60,1500968219581) 

  short len = this.getW(point_arr1, (short) 0); 
  PM.check(PMC.TRAP_ECPOINT_MULT_X_4); // 9 ms (gd60,1500968219581) 
  len = keyAgreement.generateSecret(point_arr1, (short) 0, len, outBuffer, outBufferOffset);
  PM.check(PMC.TRAP_ECPOINT_MULT_X_5); // 186 ms (gd60,1500968219581) 

  return COORD_SIZE;
}
  1. (Optional) Once inserted performance traps can be kept in code even after the performance session for later use. Alternatively, it can be easily removed (e.g., via regular expressions tool like sed).

Prerequisites and caveats

The performance profiler requires few properties:

  • Target method must be re-entrant and deterministic. The repeated calls (with the same input data) should result in the execution of the same code branch and very similar (client-side) timing measurements.
  • The method must be callable repeatedly. A separate call is performed for every performance trap. If the method is not accessible after premature interruption (caused by performance trap) due to some logical locking, a developer should send an additional command to "unlock" method before next performance call.
  • On-card operations sometimes naturally fluctuate even with exactly same input data (e.g., due to non-deterministic card protection mechanism or occasional garbage collection). Such a fluctuation is introduced measurement error which can be by detected and possibly corrected by repeated profiling sessions with the utilization of mean values from series of measurements instead of a single one.
Clone this wiki locally