JCProfilerNext is a complete rewrite of OpenCryptoProject/JCProfiler that provides a completely automated preprocessing, compilation, installation and profiling of JavaCard code on JavaCard smart cards or in the jCardSim simulator.
-
Install JDK 8 or newer.
-
Obtain a copy of the JavaCard Development Kit, e.g. from this GitHub archive maintained by Martin Paljak.
JDK | Supported JavaCard versions |
---|---|
8 |
2.2.1+ |
9-11 |
3.0.1+ |
12-19 |
3.1+ |
20+ |
none |
-
Clone this repository.
-
Run
./gradlew build
on Unix-like systems orgradlew.bat build
on Windows. -
Execute
-
directly using Gradle:
./gradlew run --args='--help'
. -
directly using built JAR:
java -jar build/libs/JCProfilerNext-1.0-SNAPSHOT.jar --help
. -
directly from distribution archives in
build/distributions
.
-
The tool can be executed in four different modes (select with --mode
):
-
custom
— Instrument the applet with user-provided code snippets. The user has to do the measurements on their own. -
memory
— Measure memory usage. -
time
(default) — Measure elapsed time. -
stats
— Collect API usage statistics.
Consider the example
method in the following class. The outer loop is clearly
not constant since its iteration count depends on the input value. On the other
hand, the inner loop is constant.
package example;
import javacard.framework.*;
public class Example extends Applet {
public static final byte INS_EXAMPLE = (byte) 0xEE;
Example() { }
public static void install(byte[] bArray, short bOffset, byte bLength) {
new Example().register();
}
@Override
public void process(APDU apdu) throws ISOException {
if (selectingApplet())
return;
switch (apdu.getBuffer()[ISO7816.OFFSET_INS]) {
case INS_EXAMPLE:
example(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void example(APDU apdu) {
short count = Util.getShort(apdu.getBuffer(), ISO7816.OFFSET_CDATA);
for (short i = 0; i < count; i++) {
short tmp = 0;
for (short k = 0; k < 50; k++) {
tmp++;
}
}
}
}
Run as:
$ ./gradlew run --args="--work-dir example --jckit jc222_kit --executable example --ins 0xEE --data-regex 00[0-9A-F]{2} --repeat-count 100"
JCProfilerNext will process all sources in the example
directory and will
also use this directory to store all intermediate results:
-
applet
- contains the built applet with corresponding CAP, JAR and JCA files -
measurements.csv
- contains the profiled method signature, card ATR, elapsed time, input APDUs and corresponding raw measurements -
measurements.html
- contains a visualisation of the measurements -
sources_instr
- contains instrumented sources -
sources_original
- contains original unchanged sources -
sources_perf
- contains sources with inserted measurements as inline comments
If you open the corresponding measurements.html
produced by JCProfilerNext, you will see that some parts of the code are indeed
not constant, namely if you inspect the corresponding histograms of traps
after the for
loops.
Consider the following source code:
package example;
import javacard.framework.*;
public class Example extends Applet {
private Example() {
// Transient Deselect
byte[] transientDeselect = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_DESELECT);
// Transient Reset
byte[] transientReset = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_RESET);
// Persistent
byte[] persistent = new byte[256];
}
public static void install(byte[] bArray, short bOffset, byte bLength) {
new Example().register();
}
@Override
public void process(APDU apdu) {}
}
Run as:
$ ./gradlew run --args="--work-dir example --jckit jc304_kit --mode memory"
JCProfilerNext will produce the same directory structure as in the time mode
above. The --executable
option is omitted because we want to measure memory
usage in the entry point class constructor. Note that the allocation of transient
deselect memory may also affect the amount of free transient memory and vice versa.
See measurements.html
for visualisation of the measurements.
Consider the following source code:
import javacard.security.KeyPair;
class Example {
public Example() {
KeyPair kp = new KeyPair(KeyPair.ALG_RSA, (short) 2048);
kp.genKeyPair();
}
}
Run as:
$ ./gradlew run --args="--work-dir example --jckit jc222_kit --mode stats"
JCProfilerNext will process all sources in the example
directory and produce
the APIstatistics.csv
file. Note that if not all imports can be resolved,
the results may not be precise, and the tool will issue an appropriate warning.
# package/outer type,type,member,frequency
javacard.security,KeyPair,,2
javacard.security,KeyPair,ALG_RSA,1
javacard.security,KeyPair,genKeyPair(),1
javacard.security,KeyPair,"KeyPair(byte,short)",1