Skip to content

Commit 776dd42

Browse files
committed
refactor: pre-compile regex patterns for performance and streamline GC event processing
1 parent a93f1c3 commit 776dd42

1 file changed

Lines changed: 119 additions & 89 deletions

File tree

src/include/inputFns.js

Lines changed: 119 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -879,110 +879,126 @@ var _inputFns = new Map([
879879
["javagc", (_res, options) => {
880880
if (!isBoolean(params.javagcjoin)) params.javagcjoin = toBoolean(_$(params.javagcjoin, "javagcjoin").isString().default(__))
881881

882+
// Pre-compile regex patterns for performance (moved outside hot path)
883+
const regexes = [
884+
// JDK 8 Allocation Failure (adjusted to handle multiline events)
885+
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\)(.+?)\[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/s,
886+
// JDK 8 style regexes
887+
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\]/,
888+
// JDK 8 with +PrintHeapAtGC
889+
/([^ ]+) (\d+\.\d+): \[(Full GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] \[ParOldGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), \[Metaspace: (\d+K)->(\d+K)\((.*?)\)\], (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/,
890+
// JDK 8 with +PrintHeapAtGC and +PrintTenuringDistribution
891+
/([^ ]+) (\d+\.\d+): \[(Full GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] \[ParOldGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), \[Metaspace: (\d+K)->(\d+K)\((.*?)\)\], (\d+\.\d+) secs\]/,
892+
// JDK 8 with +PrintTenuringDistribution
893+
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/,
894+
// JDK 8 Generic GC logs (simple format)
895+
/(\d+\.\d+): \[(GC|Full GC) \((.*?)\)\s+(\d+K)->(\d+K)\((\d+K)\), (\d+\.\d+) secs\]/,
896+
// JDK 9+ style regexes
897+
/^\[(.+)\]\s+GC\((\d+)\)\s*(.*?)\s*(\d+[GMK])->(\d+[GMK])\((\d+[GMK])\)\s*(\d+\.\d+)ms/,
898+
/^\[(.+)\]\s+GC\((\d+)\)\s*(.*?)\s*Metaspace:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)\s*NonClass:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)\s*Class:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)/,
899+
// JDK 9+ Allocation Failure
900+
/^\[(.+)\]\s+GC\((\d+)\)\s*(Allocation Failure)\s*(.*?)\s+(\d+[KMGT])->(\d+[KMGT])\((\d+[KMGT])\)\s+(\d+\.\d+)ms/,
901+
]
902+
903+
// Pre-compile patterns for head parsing
904+
const timePattern = /^\d+\.\d+s$/
905+
const timestampPattern = /\d{4}-\d{2}-\d{2}T/
906+
907+
// Helper function to avoid repeated string concatenation
908+
const fromBytesAbbr = val => isDef(val) ? ow.format.fromBytesAbbreviation(val + "B") : __
909+
882910
let _procLine = _event => {
883911
try {
884-
let regexes = [
885-
// JDK 8 Allocation Failure (adjusted to handle multiline events)
886-
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\)(.+?)\[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/s,
887-
// JDK 8 style regexes
888-
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\]/,
889-
// JDK 8 with +PrintHeapAtGC
890-
/([^ ]+) (\d+\.\d+): \[(Full GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] \[ParOldGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), \[Metaspace: (\d+K)->(\d+K)\((.*?)\)\], (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/,
891-
// JDK 8 with +PrintHeapAtGC and +PrintTenuringDistribution
892-
/([^ ]+) (\d+\.\d+): \[(Full GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] \[ParOldGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), \[Metaspace: (\d+K)->(\d+K)\((.*?)\)\], (\d+\.\d+) secs\]/,
893-
// JDK 8 with +PrintTenuringDistribution
894-
/([^ ]+) (\d+\.\d+): \[(GC) \((.*?)\) \[PSYoungGen: (\d+K)->(\d+K)\((.*?)\)\] (\d+K)->(\d+K)\((.*?)\), (\d+\.\d+) secs\] \[Times: user=(\d+\.\d+) sys=(\d+\.\d+), real=(\d+\.\d+) secs\]/,
895-
// JDK 9+ style regexes
896-
/^\[(.+)\]\s+GC\((\d+)\)\s*(.*?)\s*(\d+[GMK])->(\d+[GMK])\((\d+[GMK])\)\s*(\d+\.\d+)ms/,
897-
/^\[(.+)\]\s+GC\((\d+)\)\s*(.*?)\s*Metaspace:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)\s*NonClass:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)\s*Class:\s*(\d+[GMK])\((\d+[GMK])\)->(\d+[GMK])\((\d+[GMK])\)/,
898-
// JDK 9+ Allocation Failure
899-
/^\[(.+)\]\s+GC\((\d+)\)\s*(Allocation Failure)\s*(.*?)\s+(\d+[KMGT])->(\d+[KMGT])\((\d+[KMGT])\)\s+(\d+\.\d+)ms/,
900-
]
901912

902913
for (let index = 0; index < regexes.length; index++) {
903-
let regex = regexes[index]
904-
let match = _event.match(regex)
914+
let match = _event.match(regexes[index])
905915
if (match) {
906916
let result = {}
907917

908-
if (_event.startsWith('[')) {
918+
if (_event.charCodeAt(0) === 91) { // '[' char - faster than startsWith
909919
// JDK 9+ style parsing
910-
//result.index = index
911920
var heads = match[1].split("][")
912-
heads.forEach(head => {
913-
if (head.match(/^\d+\.\d+s$/)) {
914-
result.sinceStart = parseFloat(head.replace(/s$/, ""))
915-
} else if (head.match(/\d{4}-\d{2}-\d{2}T/)) {
921+
for (let i = 0; i < heads.length; i++) {
922+
let head = heads[i]
923+
if (timePattern.test(head)) {
924+
result.sinceStart = parseFloat(head.slice(0, -1)) // faster than replace
925+
} else if (timestampPattern.test(head)) {
916926
result.timestamp = ow.format.toDate(head, "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
917927
}
918-
})
928+
}
919929
result.gcId = parseInt(match[2])
920-
result.gcType = match[3].trim()
921-
if (result.gcType == "") result.gcType = "none"
930+
result.gcType = match[3].trim() || "none"
922931
result.durationSecs = parseFloat(match[match.length - 1]) / 1000 // convert ms to secs
923932

924933
if (index === 5) {
925934
// Match for GC pause with heap info
926-
result.heapBeforeGC = ow.format.fromBytesAbbreviation(match[4] + "B")
927-
result.heapAfterGC = ow.format.fromBytesAbbreviation(match[5] + "B")
928-
result.heapTotal = ow.format.fromBytesAbbreviation(match[6] + "B")
935+
result.heapBeforeGC = fromBytesAbbr(match[4])
936+
result.heapAfterGC = fromBytesAbbr(match[5])
937+
result.heapTotal = fromBytesAbbr(match[6])
929938
} else if (index > 5) {
930939
if (index == 6) {
931-
result.metaUsedBeforeGC = ow.format.fromBytesAbbreviation(match[4] + "B")
932-
result.metaTotalBeforeGC = ow.format.fromBytesAbbreviation(match[5] + "B")
933-
result.metaUsedAfterGC = ow.format.fromBytesAbbreviation(match[6] + "B")
934-
result.metaTotalAfterGC = ow.format.fromBytesAbbreviation(match[7] + "B")
935-
result.nonClassUsedBeforeGC = ow.format.fromBytesAbbreviation(match[8] + "B")
936-
result.nonClassTotalBeforeGC = ow.format.fromBytesAbbreviation(match[9] + "B")
937-
result.nonClassUsedAfterGC = ow.format.fromBytesAbbreviation(match[10] + "B")
938-
result.nonClassTotalAfterGC = ow.format.fromBytesAbbreviation(match[11] + "B")
939-
result.classUsedBeforeGC = ow.format.fromBytesAbbreviation(match[12] + "B")
940-
result.classTotalBeforeGC = ow.format.fromBytesAbbreviation(match[13] + "B")
941-
result.classUsedAfterGC = ow.format.fromBytesAbbreviation(match[14] + "B")
942-
result.classTotalAfterGC = ow.format.fromBytesAbbreviation(match[15] + "B")
940+
result.metaUsedBeforeGC = fromBytesAbbr(match[4])
941+
result.metaTotalBeforeGC = fromBytesAbbr(match[5])
942+
result.metaUsedAfterGC = fromBytesAbbr(match[6])
943+
result.metaTotalAfterGC = fromBytesAbbr(match[7])
944+
result.nonClassUsedBeforeGC = fromBytesAbbr(match[8])
945+
result.nonClassTotalBeforeGC = fromBytesAbbr(match[9])
946+
result.nonClassUsedAfterGC = fromBytesAbbr(match[10])
947+
result.nonClassTotalAfterGC = fromBytesAbbr(match[11])
948+
result.classUsedBeforeGC = fromBytesAbbr(match[12])
949+
result.classTotalBeforeGC = fromBytesAbbr(match[13])
950+
result.classUsedAfterGC = fromBytesAbbr(match[14])
951+
result.classTotalAfterGC = fromBytesAbbr(match[15])
943952
} else {
944-
result.heapBeforeGC = ow.format.fromBytesAbbreviation(match[4] + "B")
945-
result.heapAfterGC = ow.format.fromBytesAbbreviation(match[5] + "B")
946-
result.heapTotal = ow.format.fromBytesAbbreviation(match[6] + "B")
953+
result.heapBeforeGC = fromBytesAbbr(match[4])
954+
result.heapAfterGC = fromBytesAbbr(match[5])
955+
result.heapTotal = fromBytesAbbr(match[6])
947956
}
948957
}
949958
} else {
950959
// JDK 8 style parsing
951-
//result.index = index
952-
result.timestamp = ow.format.toDate(match[1], "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
953-
result.sinceStart = parseFloat(match[2])
954-
result.gcType = match[3] + " " + match[4]
955-
956-
//print(index)
957-
//cprint(match)
958-
if (index <= 4) {
959-
let idx = 5
960-
result.PSYoungGenBeforeGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
961-
result.PSYoungGenAfterGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
962-
result.PSYoungGenTotal = ow.format.fromBytesAbbreviation(match[idx++] + "B")
963-
964-
if (index == 2 || index == 3) {
965-
result.ParOldGenBeforeGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
966-
result.ParOldGenAfterGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
967-
result.ParOldGenTotal = ow.format.fromBytesAbbreviation(match[idx++] + "B")
968-
}
960+
if (index == 5) {
961+
// JDK 8 Generic GC logs (simple format)
962+
result.sinceStart = parseFloat(match[1])
963+
result.gcType = match[2] + " " + match[3]
964+
result.heapBeforeGC = fromBytesAbbr(match[4])
965+
result.heapAfterGC = fromBytesAbbr(match[5])
966+
result.heapTotal = fromBytesAbbr(match[6])
967+
result.durationSecs = parseFloat(match[7])
968+
} else {
969+
result.timestamp = ow.format.toDate(match[1], "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
970+
result.sinceStart = parseFloat(match[2])
971+
result.gcType = match[3] + " " + match[4]
972+
973+
if (index <= 4) {
974+
let idx = 5
975+
result.PSYoungGenBeforeGC = fromBytesAbbr(match[idx++])
976+
result.PSYoungGenAfterGC = fromBytesAbbr(match[idx++])
977+
result.PSYoungGenTotal = fromBytesAbbr(match[idx++])
978+
979+
if (index == 2 || index == 3) {
980+
result.ParOldGenBeforeGC = fromBytesAbbr(match[idx++])
981+
result.ParOldGenAfterGC = fromBytesAbbr(match[idx++])
982+
result.ParOldGenTotal = fromBytesAbbr(match[idx++])
983+
}
969984

970-
result.heapBeforeGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
971-
result.heapAfterGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
972-
result.heapTotal = ow.format.fromBytesAbbreviation(match[idx++] + "B")
985+
result.heapBeforeGC = fromBytesAbbr(match[idx++])
986+
result.heapAfterGC = fromBytesAbbr(match[idx++])
987+
result.heapTotal = fromBytesAbbr(match[idx++])
973988

974-
if (index == 2 || index == 3) {
975-
result.metaBeforeGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
976-
result.metaAfterGC = ow.format.fromBytesAbbreviation(match[idx++] + "B")
977-
result.metaTotal = ow.format.fromBytesAbbreviation(match[idx++] + "B")
978-
}
989+
if (index == 2 || index == 3) {
990+
result.metaBeforeGC = fromBytesAbbr(match[idx++])
991+
result.metaAfterGC = fromBytesAbbr(match[idx++])
992+
result.metaTotal = fromBytesAbbr(match[idx++])
993+
}
979994

980-
result.durationSecs = parseFloat(match[idx++])
995+
result.durationSecs = parseFloat(match[idx++])
981996

982-
if (index == 0 || index == 2 || index == 4) {
983-
result.userTime = parseFloat(match[idx++])
984-
result.sysTime = parseFloat(match[idx++])
985-
result.realTime = parseFloat(match[idx++])
997+
if (index == 0 || index == 2 || index == 4) {
998+
result.userTime = parseFloat(match[idx++])
999+
result.sysTime = parseFloat(match[idx++])
1000+
result.realTime = parseFloat(match[idx++])
1001+
}
9861002
}
9871003
}
9881004
}
@@ -998,34 +1014,48 @@ var _inputFns = new Map([
9981014
_showTmpMsg()
9991015
if (isString(_res)) {
10001016
let lines = _res.split("\n")
1001-
let gcStartPattern = /^(\[\d+|\d{4}-\d{2}-\d{2}T)/ // Matches lines starting with '[\d+' or a timestamp
1017+
let gcStartPattern = /^(\[?\d+|\d{4}-\d{2}-\d{2}T)/ // Matches lines starting with '[\d+' or a timestamp
10021018

10031019
let gcEvents = []
1004-
let currentEvent = []
1020+
let currentEvent = ""
1021+
let hasCurrentEvent = false
10051022

1006-
for (let line of lines) {
1023+
for (let i = 0; i < lines.length; i++) {
1024+
let line = lines[i]
10071025
if (gcStartPattern.test(line)) {
10081026
// New GC event detected
1009-
if (currentEvent.length > 0) {
1010-
gcEvents.push(currentEvent.join("\n"))
1027+
if (hasCurrentEvent) {
1028+
gcEvents.push(currentEvent)
10111029
}
1012-
currentEvent = [line]
1030+
currentEvent = line
1031+
hasCurrentEvent = true
10131032
} else {
10141033
// Continuation of the current GC event
1015-
currentEvent.push(line)
1034+
if (hasCurrentEvent) {
1035+
currentEvent += "\n" + line
1036+
}
10161037
}
10171038
}
10181039
// Add the last GC event
1019-
if (currentEvent.length > 0) {
1020-
gcEvents.push(currentEvent.join("\n"))
1040+
if (hasCurrentEvent) {
1041+
gcEvents.push(currentEvent)
10211042
}
10221043

1023-
let results = gcEvents.map(_procLine).filter(r => isMap(r))
1044+
// Process events and filter valid results in one pass
1045+
let results = []
1046+
for (let i = 0; i < gcEvents.length; i++) {
1047+
let result = _procLine(gcEvents[i])
1048+
if (isMap(result)) {
1049+
results.push(result)
1050+
}
1051+
}
10241052

10251053
if (params.javagcjoin) {
10261054
_$o(results, options, true)
10271055
} else {
1028-
results.forEach(result => _$o(result, options, true))
1056+
for (let i = 0; i < results.length; i++) {
1057+
_$o(results[i], options, true)
1058+
}
10291059
}
10301060
} else {
10311061
_exit(-1, "javagc is only supported with a string input.")
@@ -1410,4 +1440,4 @@ var _inputFns = new Map([
14101440
_showTmpMsg()
14111441
_$o(jsonParse(_res, __, __, isString(_res)), options)
14121442
}]
1413-
])
1443+
])

0 commit comments

Comments
 (0)