Skip to content

Replace a regex-based SMAP parser with a hand-crafted one #8730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 30, 2025
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.datadog.profiling.controller.openjdk.events;

/**
* A simple stateful parser for an smap entry.<br>
* The values are delimited by spaces and/or dashes. The parser allows consuming next long/string
* value, skipping over the current value, skipping to the next value, and slurping the rest of the
* current value.<br>
* The implementation is minimalistic with the accent on reducing the number of allocations.
*/
final class SimpleParser {
private final String line;

private int pos;

public SimpleParser(String line) {
this.line = line;
this.pos = 0;
}

void skipToNextValue(boolean acceptDash) {
int limit = line.length();
while (pos < limit && isDelimiter(line.charAt(pos), acceptDash)) {
pos++;
}
}

void skipValue(boolean acceptDash) {
int limit = line.length();
char c = 0;
while (pos < limit && !isDelimiter(line.charAt(pos), acceptDash)) {
pos++;
}
}

long nextLongValue(int base) {
if (base != 10 && base != 16) {
throw new UnsupportedOperationException("Unsupported base: " + base);
}
int limit = line.length();
skipToNextValue(true);
if (pos == limit) {
pos = -1;
return -1;
}
long val = 0;
char c = 0;
while (pos < limit && !isDelimiter(c = line.charAt(pos), true)) {
if (c < '0' || c > '9') {
if (base == 10 || (c < 'a' || c > 'f')) {
skipValue(true);
return -1;
}
}
int digit = c >= 'a' ? 10 + (c - 'a') : (c - '0');
val = val * base + digit;
pos++;
}
return val;
}

String nextStringValue() {
int limit = line.length();
skipToNextValue(false);
if (pos == limit) {
pos = -1;
return null;
}
long val = 0;
StringBuilder sb = new StringBuilder();
char c = 0;
while (pos < limit && !isDelimiter(c = line.charAt(pos), false)) {
sb.append(c);
pos++;
}
return sb.toString();
}

String slurpStringValue() {
int limit = line.length();
skipToNextValue(false);
if (pos == limit) {
pos = -1;
return null;
}
return line.substring(pos).trim();
}

private static boolean isDelimiter(char c, boolean acceptDash) {
return c == ' ' || (acceptDash && c == '-');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,120 +19,120 @@
public class SmapEntryEvent extends Event {

@Label("Region Start Address")
private final long startAddress;
long startAddress;

@Label("Region End Address")
private final long endAddress;
long endAddress;

@Label("Region Permissions")
private final String perms;
String perms;

@Label("Offset into mapping")
private final long offset;
long offset;

@Label("Device")
private final String dev;
String dev;

@Label("INode ID")
private final int inodeID;
int inodeID;

@Label("Path associated with mapping")
private final String pathname;
String pathname;

@Label("Mapping Size")
private final long size;
long size;

@Label("Page Size")
private final long kernelPageSize;
long kernelPageSize;

@Label("Memory Management Unit Page Size")
private final long mmuPageSize;
long mmuPageSize;

@Label("Resident Set Size")
@DataAmount
private final long rss;
long rss;

@Label("Proportional Set Size")
@DataAmount
private final long pss;
long pss;

@Label("Dirty Proportional Set Size")
@DataAmount
private final long pssDirty;
long pssDirty;

@Label("Shared Clean Pages")
private final long sharedClean;
long sharedClean;

@Label("Shared Dirty Pages")
@DataAmount
private final long sharedDirty;
long sharedDirty;

@Label("Private Clean Pages")
@DataAmount
private final long privateClean;
long privateClean;

@Label("Private Dirty Pages")
@DataAmount
private final long privateDirty;
long privateDirty;

@Label("Referenced Memory")
private final long referenced;
long referenced;

@Label("Anonymous Memory")
@DataAmount
private final long anonymous;
long anonymous;

@Label("Kernel Same-page Merging")
@DataAmount
private final long ksm;
long ksm;

@Label("Lazily Freed Memory")
@DataAmount
private final long lazyFree;
long lazyFree;

@Label("Anon Huge Pages")
@DataAmount
private final long anonHugePages;
long anonHugePages;

@Label("Shared Memory Huge Pages")
@DataAmount
private final long shmemPmdMapped;
long shmemPmdMapped;

@Label("Page Cache Huge Pages")
@DataAmount
private final long filePmdMapped;
long filePmdMapped;

@Label("Shared Huge Pages")
@DataAmount
private final long sharedHugetlb;
long sharedHugetlb;

@Label("Private Huge Pages")
@DataAmount
private final long privateHugetlb;
long privateHugetlb;

@Label("Swap Size")
@DataAmount
private final long swap;
long swap;

@Label("Proportional Swap Size")
@DataAmount
private final long swapPss;
long swapPss;

@Label("Locked Memory")
@DataAmount
private final long locked;
long locked;

@Label("THP Eligible")
private final boolean thpEligible;
boolean thpEligible;

@Label("VM Flags")
private final String vmFlags;
String vmFlags;

@Label("Encountered foreign keys")
private final boolean encounteredForeignKeys;
boolean encounteredForeignKeys;

@Label("NMT Category")
private final String nmtCategory;
String nmtCategory;

public SmapEntryEvent() {
startAddress = 0;
Expand Down
Loading
Loading