Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/workflows/build-artifacts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
name: Build artifacts

on:
push:
branches: ['**']
tags: ['v*']

jobs:
build-jar:
name: Build JAR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6

- name: Determine version
id: version
shell: bash
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
else
echo "value=" >> "$GITHUB_OUTPUT"
fi

- name: Build JAR
run: ./gradlew jar -Pversion=${{ steps.version.outputs.value }}

- uses: actions/upload-artifact@v4
with:
name: JCProfilerNext-jar
path: build/libs/*.jar

build-native:
name: Build native binary (${{ matrix.name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
include:
- os: ubuntu-latest
name: Linux
artifact: JCProfilerNext-linux-x64
- os: windows-latest
name: Windows
artifact: JCProfilerNext-windows-x64
steps:
- uses: actions/checkout@v6

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6

- name: Determine version
id: version
shell: bash
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
else
echo "value=" >> "$GITHUB_OUTPUT"
fi

- name: Build native app-image
run: ./gradlew jpackage -Pversion=${{ steps.version.outputs.value }}

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: build/jpackage/JCProfilerNext
25 changes: 24 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,37 @@ Prerequisites
|===


Installation
------------
Prebuilt artifacts are produced by the
link:https://github.com/crocs-muni/JCProfilerNext/actions/workflows/build-artifacts.yml[`Build artifacts`]
workflow on every push and for every pushed `v*` tag, and can be downloaded
from that workflow run's "Artifacts" section. Tagged versions are additionally
published on the
link:https://github.com/crocs-muni/JCProfilerNext/releases[GitHub Releases page].

* `JCProfilerNext-<version>.jar` -- a self-contained JAR. Requires a JDK 8 or
newer to be installed; run with `java -jar JCProfilerNext-<version>.jar --help`.
* `JCProfilerNext-linux-x64.zip` / `JCProfilerNext-windows-x64.zip` -- a
self-contained native application bundling its own Java runtime, so no JDK
installation is required. After extracting, run
`./JCProfilerNext/bin/JCProfilerNext --help` on Linux or
`JCProfilerNext\JCProfilerNext.exe --help` on Windows. Each archive also
ships a man page at `JCProfilerNext/man/JCProfilerNext.1`; view it with
`man JCProfilerNext/man/JCProfilerNext.1` or install it into your system's
man path.

Compilation
-----------
. Clone this repository.
. Run `./gradlew build` on Unix-like systems or `gradlew.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 using built JAR: `java -jar build/libs/JCProfilerNext-<version>.jar --help`.
.. directly from distribution archives in `build/distributions`.
.. as a self-contained native application: run `./gradlew jpackage`, which
produces an application image bundling a JRE in `build/jpackage/JCProfilerNext`
(requires JDK 17 or newer to build, due to the `jpackage` tool).

Execution modes
---------------
Expand Down
41 changes: 40 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
// TODO: shadow plugin?

group = 'org.crocs'
version = '1.0-SNAPSHOT'
version = findProperty('version') ?: '1.0-SNAPSHOT'

java {
sourceCompatibility = JavaVersion.VERSION_1_8
Expand Down Expand Up @@ -69,6 +69,9 @@ compileJava {

application {
mainClass = 'jcprofiler.Main'
applicationDistribution.from('man') {
into 'man'
}
}

run {
Expand All @@ -95,3 +98,39 @@ jar {
test {
useJUnitPlatform()
}

tasks.register('jpackage', Exec) {
dependsOn jar

def appVersion = version.toString().replace('-SNAPSHOT', '')
def destDir = layout.buildDirectory.dir('jpackage').get().asFile

doFirst {
destDir.deleteDir()
}

def args = [
'--type', 'app-image',
'--input', tasks.jar.destinationDirectory.get().asFile,
'--main-jar', tasks.jar.archiveFileName.get(),
'--main-class', 'jcprofiler.Main',
'--name', 'JCProfilerNext',
'--app-version', appVersion,
'--dest', destDir
]

// JCProfilerNext is a CLI tool, so it needs a console attached on Windows;
// jpackage otherwise builds a windowed launcher with no stdio.
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
args << '--win-console'
}

commandLine(['jpackage'] + args)

doLast {
copy {
from 'man'
into "${destDir}/JCProfilerNext/man"
}
}
}
157 changes: 157 additions & 0 deletions man/JCProfilerNext.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
.TH JCPROFILERNEXT 1 "2024" "JCProfilerNext" "User Commands"
.SH NAME
JCProfilerNext \- automated profiling of JavaCard applets
.SH SYNOPSIS
.B JCProfilerNext
.B \-\-work\-dir
.I DIR
.B \-\-jckit
.I JCKIT_DIR
[\fIOPTIONS\fR]
.SH DESCRIPTION
JCProfilerNext automates the preprocessing, compilation, installation, and
profiling of JavaCard applets on real smart cards or in the jCardSim simulator.
.PP
After a successful run the tool writes to \fIwork\-dir\fR:
.IP \(bu 4
\fBmeasurements.csv\fR \(en raw per-trap measurements
.IP \(bu 4
\fBmeasurements.html\fR \(en interactive per-line histogram visualisation
.IP \(bu 4
\fBsources_perf/\fR \(en original sources annotated with inline measurements
.IP \(bu 4
\fBAPIstatistics.csv\fR \(en API call frequency table (stats mode only)
.SH OPTIONS
.SS General
.TP
.BR \-h ", " \-\-help
Show help message.
.TP
.BR \-d ", " \-\-debug
Enable debug log output.
.TP
.BR \-w " " \fIDIR\fR ", " \-\-work\-dir " " \fIDIR\fR
Path to the working directory containing the applet sources. \fB(required)\fR
.TP
.BI \-\-jckit " DIR"
Path to the root directory of a JavaCard Development Kit. \fB(required)\fR
.TP
.BI \-\-mode " MODE"
Profiling mode. Accepted values: \fBcustom\fR, \fBmemory\fR, \fBtime\fR, \fBstats\fR.
Default: \fBtime\fR.
.TP
.BI \-\-repeat\-count " N"
Number of profiling rounds (time and custom modes). Default: \fB1000\fR.
.TP
.B \-\-simulator
Use the jCardSim simulator instead of a real card.
.SS Stage control
.TP
.BI \-\-start\-from " STAGE"
Begin execution at the given stage. Values: instrumentation, compilation,
installation, profiling, visualisation. Default: \fBinstrumentation\fR.
.TP
.BI \-\-stop\-after " STAGE"
Stop execution after the given stage. Default: \fBvisualisation\fR.
.SS Applet identification
.TP
.BI \-\-executable " METHOD"
Unqualified method name to profile (e.g.\& \fBmyMethod\fR).
Omit to profile the entry-point class constructor (constructor profiling requires custom or memory mode).
.TP
.BI \-\-entry\-point " CLASS"
Fully-qualified class name of the applet entry point (e.g.\& \fBcom.example.MyApplet\fR).
Required when the working directory contains more than one applet class.
.TP
.BI \-\-install\-params " HEX"
Parameters for the applet install method (hex string).
.SS APDU configuration
.TP
.BI \-\-cla " HEX"
Applet CLA byte in hex. Default: \fB0x00\fR.
.TP
.BI \-\-ins " HEX"
Applet instruction byte in hex. Default: \fB0x00\fR.
.TP
.BI \-\-p1 " HEX"
Applet P1 byte in hex. Default: \fB0x00\fR.
.TP
.BI \-\-p2 " HEX"
Applet P2 byte in hex. Default: \fB0x00\fR.
.TP
.BI \-\-reset\-ins " HEX"
Instruction byte used to reset the applet between rounds.
.TP
.BI \-\-key " HEX"
Authentication key for the card (hex string).
.SS Input data
.TP
.BI \-\-data\-regex " REGEX"
Regex pattern (in hex) used to generate input data. Mutually exclusive with
\fB\-\-data\-file\fR.
.TP
.BI \-\-data\-file " FILE"
File containing explicit input data in hex (one value per line). Mutually
exclusive with \fB\-\-data\-regex\fR.
.TP
.BI \-\-input\-division " MODE"
Divide generated inputs into two categories. Values: effectiveBitLength,
hammingWeight, none. Default: \fBnone\fR.
.SS Output
.TP
.BI \-\-time\-unit " UNIT"
Time unit for result visualisation (time mode). Values: nano, micro, milli,
sec. Default: \fBmicro\fR.
.SS Custom mode
.TP
.BI \-\-custom\-pm " FILE"
Path to the custom PM class (custom mode only, required).
.TP
.BI \-\-custom\-handler " FILE"
Path to the INS_PERF_CUSTOM handler block file (custom mode only).
.SS Dependencies
.TP
.BI \-\-jar " FILE"
Additional JAR file to add to the JavaCard class path (can be repeated).
.SH EXAMPLES
Profile the \fIexample\fR method using the simulator:
.PP
.RS
.nf
JCProfilerNext --work-dir my_applet --jckit path/to/jc222_kit \\
--executable example --ins 0xEE \\
--data-regex 00[0-9A-F]{2} --simulator
.fi
.RE
.PP
Measure constructor memory usage:
.PP
.RS
.nf
JCProfilerNext --work-dir my_applet --jckit path/to/jc304_kit --mode memory
.fi
.RE
.PP
Collect API usage statistics:
.PP
.RS
.nf
JCProfilerNext --work-dir my_applet --jckit path/to/jc222_kit --mode stats
.fi
.RE
.SH "JDK / JAVACARD COMPATIBILITY"
.TS
tab(|);
l l.
JDK|Supported JavaCard versions
8|2.2.1+
9\(en11|3.0.1+
12\(en19|3.1+
20+|none
.TE
.SH "REPORTING BUGS"
Re-run with \fB\-\-debug\fR, save the output, and open an issue at:
.br
https://github.com/crocs-muni/JCProfilerNext/issues
.SH "SEE ALSO"
The full documentation is in \fBREADME.adoc\fR in the project root.
Loading