Skip to content

Commit ee61f37

Browse files
committed
perf: parse trace_id hex without allocating substrings
1 parent c0d36fd commit ee61f37

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

lib/src/main/java/io/otel/pyroscope/PyroscopeOtelSpanProcessor.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ public void onStart(Context parentContext, ReadWriteSpan span) {
6363

6464
span.setAttribute(ATTRIBUTE_KEY_PROFILE_ID, strProfileId);
6565
asprof.setTracingContext(spanId, spanName);
66+
// W3C trace ID is 32 hex chars (128 bits). Parse directly into two longs
67+
// to avoid the String#substring allocations on this hot path.
6668
String traceId = span.getSpanContext().getTraceId();
67-
asprof.setTraceId(Long.parseUnsignedLong(traceId.substring(0, 16), 16),
68-
Long.parseUnsignedLong(traceId.substring(16, 32), 16));
69+
asprof.setTraceId(parseHex64(traceId, 0), parseHex64(traceId, 16));
6970
}
7071

7172
@Override
@@ -88,6 +89,25 @@ public static long parseSpanId(String strProfileId) {
8889
}
8990
}
9091

92+
static long parseHex64(String s, int offset) {
93+
long result = 0L;
94+
for (int i = 0; i < 16; i++) {
95+
int c = s.charAt(offset + i);
96+
int nibble;
97+
if (c >= '0' && c <= '9') {
98+
nibble = c - '0';
99+
} else if (c >= 'a' && c <= 'f') {
100+
nibble = c - 'a' + 10;
101+
} else if (c >= 'A' && c <= 'F') {
102+
nibble = c - 'A' + 10;
103+
} else {
104+
throw new NumberFormatException("invalid hex char in trace_id at index " + (offset + i));
105+
}
106+
result = (result << 4) | nibble;
107+
}
108+
return result;
109+
}
110+
91111
public static boolean isRootSpan(ReadableSpan span) {
92112
SpanContext parent = span.getParentSpanContext();
93113
boolean noParent = parent == SpanContext.getInvalid();

0 commit comments

Comments
 (0)