From e393f237a5967386717a64b17826be166ea40beb Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 1 Jul 2025 13:12:53 +0200 Subject: [PATCH] Update iprof version to include instanceof profiles. --- .../native-image/PGO-IprofFileFormat.md | 42 +- .../assets/iprof-v1.1.0.schema.json | 374 ++++++++++++++++++ 2 files changed, 408 insertions(+), 8 deletions(-) create mode 100644 docs/reference-manual/native-image/assets/iprof-v1.1.0.schema.json diff --git a/docs/reference-manual/native-image/PGO-IprofFileFormat.md b/docs/reference-manual/native-image/PGO-IprofFileFormat.md index eea34cfdad26..73eacc9f8015 100644 --- a/docs/reference-manual/native-image/PGO-IprofFileFormat.md +++ b/docs/reference-manual/native-image/PGO-IprofFileFormat.md @@ -17,33 +17,34 @@ This document outlines the structure and semantics of the _iprof_ file format. ## Structure -The full schema of the JSON format used for _iprof_ files can be found in the [iprof-v1.0.0.schema.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/iprof-v1.0.0.schema.json) document. +The full schema of the JSON format used for _iprof_ files can be found in the [iprof-v1.1.0.schema.json](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/iprof-v1.1.0.schema.json) document. This JSON schema fully defines the _iprof_ file format and can be used to validate the structure of an arbitrary _iprof_ file. A minimal valid _iprof_ file consists of a JSON object containing 3 fields: `types`, `methods` and `version`. -The following is a minimal valid _iprof_ file for the current version (`1.0.0`). +The following is a minimal valid _iprof_ file for the current version (`1.1.0`). ```json { - "version": "1.0.0", + "version": "1.1.0", "types": [], "methods": [] } ``` In addition to these fields, the _iprof_ file may optionally contain others that provide information on various run-time profiles. -The following is an example of a fully populated _iprof_ file (version `1.0.0`) with the actual content of each of the fields replaced with `...`. +The following is an example of a fully populated _iprof_ file (version `1.1.0`) with the actual content of each of the fields replaced with `...`. ```json { - "version": "1.0.0", + "version": "1.1.0", "types": [...], "methods": [...], "monitorProfiles": [...], "virtualInvokeProfiles": [...], "callCountProfiles": [...], "conditionalProfiles": [...], - "samplingProfiles": [...] + "samplingProfiles": [...], + "instanceofProfiles": [...], } ``` @@ -115,11 +116,11 @@ The _iprof_ format uses a semantic versioning scheme (ie. `major.minor.patch`) t The major version is updated for breaking changes (for example, a new way of encoding the information), minor for non-breaking ones (for example, adding a new optional field in the top-level JSON object), and the patch version is updated for minor fixes that should not impact any client. -The current version of the _iprof_ file format is `1.0.0`, which can be seen in the _iprof_ file from the example application. +The current version of the _iprof_ file format is `1.1.0`, which can be seen in the _iprof_ file from the example application. ```json ... - "version": "1.0.0", + "version": "1.1.0", ... ``` @@ -713,6 +714,31 @@ In this case, it means that the context described in the previous paragraph was The other object in the sampling profiles array contains a different context and this sample was seen only once. Understanding the nature of this sample is left as an exercise to the reader. +## Instance-of Profiles + +> Note: Instance-of profiles were added in the _iprof_ file format version 1.1.0. They are not present in version 1.0.0. + +Instance-of profiles contain information on the run-time types of values that are checked at `instanceof` operators. +Specifically, they record how many times a particular run-time type was encountered at a given `instanceof` operation. +Thus, instance-of profiling information can be stored in the same format as [Virtual Invoke Profiles](#virtual-invoke-profiles). +The only difference is that the resulting type histogram in the `records` part describes the types seen at `instanceof` checks, rather than the receiver types of virtual method calls. +Consider the following Java code: + +```java + public class A {} + public class B extends A {} + + public static void doForA(Object obj) { + if(obj instanceof A) { + doSomething(obj); + } + } +``` + +The `records` section of the profile will include all types (e.g., `A`, `B`, `Object`, `String`) encountered at run time for the `obj` variable, together with their occurrence counts. +Thus, the length of the `records` array for instance-of profiles is always a multiple of 2, +since the values represent a type ID and count pair. + ## Related Documentation - [PGO](PGO.md) - [Optimize a Native Executable with Profile-Guided Optimization](guides/optimize-native-executable-with-pgo.md) diff --git a/docs/reference-manual/native-image/assets/iprof-v1.1.0.schema.json b/docs/reference-manual/native-image/assets/iprof-v1.1.0.schema.json new file mode 100644 index 000000000000..60fb8c027015 --- /dev/null +++ b/docs/reference-manual/native-image/assets/iprof-v1.1.0.schema.json @@ -0,0 +1,374 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://graalvm.org/iprof.schema.json", + "title": "Root object of an iprof file.", + "description": "Stores profiling information used for GraalVM PGO.", + "type": "object", + "required": [ + "methods", + "types", + "version" + ], + "properties": { + "types": { + "$id": "#root/types", + "title": "Types", + "type": "array", + "default": [], + "description": "Information about types required to interpret the profile.", + "items":{ + "$id": "#root/types/items", + "title": "Items", + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$id": "#root/types/items/id", + "title": "Id", + "type": "integer", + "description": "Per-file-unique ID for the type.", + "examples": [ + 1 + ] + }, + "name": { + "$id": "#root/types/items/name", + "title": "Name", + "type": "string", + "description": "Fully qualified name of the type.", + "examples": [ + "java.util.ArrayList" + ], + "pattern": "^.*$" + } + } + } + }, + "methods": { + "$id": "#root/methods", + "title": "Methods", + "type": "array", + "default": [], + "description": "Information about methods required to interpret the profile.", + "items":{ + "$id": "#root/methods/items", + "title": "Method", + "type": "object", + "required": [ + "id", + "name", + "signature" + ], + "properties": { + "id": { + "$id": "#root/methods/items/id", + "title": "Id", + "type": "integer", + "description": "Per-file-unique ID for the method.", + "examples": [ + 2 + ] + }, + "name": { + "$id": "#root/methods/items/name", + "title": "Name", + "type": "string", + "examples": [ + "main" + ], + "pattern": "^.*$" + }, + "signature": { + "$id": "#root/methods/items/signature", + "title": "Signature", + "type": "array", + "description": "Sequence of type IDs from the types list, consisting of declaration class ID, return type ID, and type IDs in the signature, in that order.", + "items":{ + "$id": "#root/methods/items/signature/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + } + } + } + } + }, + "callCountProfiles": { + "$id": "#root/callCountProfiles", + "title": "Call count profiles", + "type": "array", + "default": [], + "description": "Information about how many times a method was executed in all it's inlining contexts.", + "items":{ + "$id": "#root/callCountProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/callCountProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "List of method:bci pairs, separated with <. Caller is to the right of the callee.", + "examples": [ + "2:0", + "1:0<4:6" + ], + "pattern": "^[0-9]+:0(<[0-9]+:-?[0-9]+)*$" + }, + "records": { + "$id": "#root/callCountProfiles/items/records", + "title": "Records", + "type": "array", + "items":{ + "$id": "#root/callCountProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + }, + "description": "Single-value array containing the call count of the method in the given context.", + "minItems": 1, + "maxItems": 1 + } + } + } + }, + "conditionalProfiles": { + "$id": "#root/conditionalProfiles", + "title": "Conditional profiles", + "type": "array", + "default": [], + "description": "Information about how many times each branch of a conditional was taken.", + "items":{ + "$id": "#root/conditionalProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/callCountProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "List of method:bci pairs, separated with <. Caller is to the right of the callee.", + "examples": [ + "2:0", + "1:0<4:6" + ], + "pattern": "^[0-9]+:-?[0-9]+(<[0-9]+:-?[0-9]+)*$" + }, + "records": { + "$id": "#root/callCountProfiles/items/records", + "title": "Records", + "type": "array", + "description": "Array of integer values containing a series of triplets: BCI, index (order) and execution count for that branch.", + "items":{ + "$id": "#root/callCountProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + } + } + } + } + }, + "monitorProfiles": { + "$id": "#root/monitorProfiles", + "title": "Monitor profiles", + "type": "array", + "default": [], + "description": "Information about how many times a type was synchronized on.", + "items":{ + "$id": "#root/monitorProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/monitorProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "Dummy context.", + "examples": [ + "0:0" + ], + "pattern": "^0:0$" + }, + "records": { + "$id": "#root/monitorProfiles/items/records", + "title": "Records", + "type": "array", + "description": "Array of integer values containing a series of pairs: type id and number of times that type was used for synchronization.", + "default": [], + "items":{ + "$id": "#root/monitorProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + } + } + } + } + }, + "samplingProfiles": { + "$id": "#root/samplingProfiles", + "title": "Samplingprofiles", + "type": "array", + "default": [], + "description": "Periodically gathered run-time call stacks (i.e. samples).", + "items":{ + "$id": "#root/samplingProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/samplingProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "List of method:bci pairs, separated with <. Caller is to the right of the callee.", + "examples": [ + "2:0", + "1:0<4:6" + ], + "pattern": "^[0-9]+:-?[0-9]+(<[0-9]+:-?[0-9]+)*$" + }, + "records": { + "$id": "#root/samplingProfiles/items/records", + "title": "Records", + "type": "array", + "description": "Single-value array containing the number of times the given context was recorded at run time.", + "items":{ + "$id": "#root/samplingProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + }, + "minItems": 1, + "maxItems": 1 + } + } + } + }, + "version": { + "$id": "#root/version", + "title": "Version", + "type": "string", + "default": "", + "examples": [ + "1.0.0" + ], + "pattern": "^[0-9]+.[0-9]+.[0-9]+$" + }, + "virtualInvokeProfiles": { + "$id": "#root/virtualInvokeProfiles", + "title": "Virtual invoke profiles", + "type": "array", + "default": [], + "description": "Information about the run-time receiver types of virutal invokes.", + "items":{ + "$id": "#root/virtualInvokeProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/virtualInvokeProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "List of method:bci pairs, separated with <. Caller is to the right of the callee.", + "examples": [ + "2:0", + "1:0<4:6" + ], + "pattern": "^[0-9]+:-?[0-9]+(<[0-9]+:-?[0-9]+)*$" + }, + "records": { + "$id": "#root/virtualInvokeProfiles/items/records", + "title": "Records", + "type": "array", + "description": "Array of integer values containing a series of pairs: type id and number of times the virtual call receiver was of that type.", + "items":{ + "$id": "#root/virtualInvokeProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + } + } + } + } + }, + "instanceofProfiles": { + "$id": "#root/instanceofProfiles", + "title": "Instanceof profiles", + "type": "array", + "default": [], + "description": "Information about the run-time types of values that are checked at instanceofs.", + "items":{ + "$id": "#root/instanceofProfiles/items", + "title": "Items", + "type": "object", + "required": [ + "ctx", + "records" + ], + "properties": { + "ctx": { + "$id": "#root/instanceofProfiles/items/ctx", + "title": "Context", + "type": "string", + "description": "List of method:bci pairs, separated with <. Caller is to the right of the callee.", + "examples": [ + "2:0", + "1:0<4:6" + ], + "pattern": "^[0-9]+:-?[0-9]+(<[0-9]+:-?[0-9]+)*$" + }, + "records": { + "$id": "#root/instanceofProfiles/items/records", + "title": "Records", + "type": "array", + "description": "Array of integer values containing a series of pairs: type id and number of times the particular type was seen at the instanceof.", + "items":{ + "$id": "#root/instanceofProfiles/items/records/items", + "title": "Items", + "type": "integer", + "examples": [ + 1 + ] + } + } + } + } + } + } +}