Skip to content

Fix performance tests #6665

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 2 commits into from
May 23, 2024
Merged
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
98 changes: 61 additions & 37 deletions integration-tests/tests/src/performance-tests/property-reads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,53 +16,59 @@
//
////////////////////////////////////////////////////////////////////////////

import Realm, { ObjectSchema, PropertySchema } from "realm";
import { expect } from "chai";
import Realm, { BSON, ObjectSchema, PropertySchema, PropertySchemaShorthand } from "realm";

import { describePerformance } from "../utils/benchmark";

type Value = ((realm: Realm) => unknown) | unknown;

function getTypeName(type: Realm.PropertySchemaShorthand | Realm.PropertySchema) {
if (typeof type === "object") {
const prefix = type.optional ? "optional " : "";
if (type.objectType) {
return prefix + `${type.type}<${type.objectType}>`;
} else {
return prefix + type.type;
}
} else {
return type;
const COLLECTION_MARKERS: Readonly<Record<string, string>> = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Widening the type here for better ergonomics when bracket accessing it by an unknown string (and that's the only way it's used in this file).

list: "[]",
dictionary: "{}",
set: "<>",
};

/**
* Get a representative consistent name of the type depending on the schema.
*
* @example
* "int?[]" -> "int?[]"
* { type: "list", objectType: "int", optional: true } -> "int?[]"
*/
function getTypeDisplayName(schema: PropertySchemaShorthand | PropertySchema) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming from getTypeName to disambiguate it from the various usages of type we have.

const isShorthand = typeof schema === "string";
if (isShorthand) {
return schema;
}

const optionalMarker = schema.optional ? "?" : "";
const collectionMarker = COLLECTION_MARKERS[schema.type] ?? "";

return (schema.objectType || schema.type) + optionalMarker + collectionMarker;
}

type TestParameters = {
name?: string;
type: Realm.PropertySchemaShorthand | Realm.PropertySchema;
propertySchema: PropertySchemaShorthand | PropertySchema;
value: Value;
schema?: Realm.ObjectSchema[];
extraObjectSchemas?: ObjectSchema[];
};

function describeTypeRead({ type, value, schema = [] }: TestParameters) {
const typeName = getTypeName(type);
const objectSchemaName = type + "Class";
const propertyName = type + "Prop";
function describeTypeRead({ propertySchema, value, extraObjectSchemas = [] }: TestParameters) {
const typeDisplayName = getTypeDisplayName(propertySchema);
const objectSchemaName = typeDisplayName + "Class";
const propertyName = typeDisplayName + "Prop";

const defaultSchema: ObjectSchema = {
name: objectSchemaName,
properties: {
[propertyName]:
typeof type === "object"
? type
: ({
type,
optional: true,
} as PropertySchema),
[propertyName]: propertySchema,
},
};

describePerformance(`reading property of type '${typeName}'`, {
schema: [defaultSchema, ...schema],
benchmarkTitle: `reads ${typeName}`,
describePerformance(`reading property of type '${typeDisplayName}'`, {
schema: [defaultSchema, ...extraObjectSchemas],
benchmarkTitle: `reads ${typeDisplayName}`,
before(this: Partial<RealmObjectContext> & RealmContext & Mocha.Context) {
this.realm.write(() => {
this.object = this.realm.create(objectSchemaName, {
Expand All @@ -76,15 +82,17 @@ function describeTypeRead({ type, value, schema = [] }: TestParameters) {
},
test(this: RealmObjectContext) {
const value = this.object[propertyName];
// Performing a check to avoid the get of the property to be optimized away.
if (typeof value === "undefined") {
// Performing a check to avoid the get of the property to be optimized away
throw new Error("Expected a value");
}
},
});
}

const cases: Array<TestParameters | [Realm.PropertySchemaShorthand | Realm.PropertySchema, Value]> = [
type SchemaValuePair = [PropertySchemaShorthand | PropertySchema, Value];

const cases: (TestParameters | SchemaValuePair)[] = [
["bool?", true],
["bool", true],
["int?", 123],
Expand All @@ -93,15 +101,15 @@ const cases: Array<TestParameters | [Realm.PropertySchemaShorthand | Realm.Prope
["double?", 123.456],
["double", 123.456],
["string?", "Hello!"],
["decimal128?", new Realm.BSON.Decimal128("123")],
["objectId?", new Realm.BSON.ObjectId("0000002a9a7969d24bea4cf4")],
["uuid?", new Realm.BSON.UUID()],
["decimal128?", new BSON.Decimal128("123")],
["objectId?", new BSON.ObjectId("0000002a9a7969d24bea4cf4")],
["uuid?", new BSON.UUID()],
["date?", new Date("2000-01-01")],
["data?", new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09])],
{
type: "Car",
schema: [{ name: "Car", properties: { model: "string" } }],
propertySchema: "Car",
value: (realm: Realm) => realm.create("Car", { model: "VW Touran" }),
extraObjectSchemas: [{ name: "Car", properties: { model: "string" } }],
},
["bool?[]", []],
["bool?<>", []],
Expand All @@ -111,10 +119,26 @@ const cases: Array<TestParameters | [Realm.PropertySchemaShorthand | Realm.Prope
describe.skipIf(environment.performance !== true, "Property read performance", () => {
for (const c of cases) {
if (Array.isArray(c)) {
const [type, value] = c;
describeTypeRead({ type, value });
const [propertySchema, value] = c;
describeTypeRead({ propertySchema, value });
} else {
describeTypeRead(c);
}
}

describe("Helpers", () => {
it("getTypeDisplayName()", function () {
expect(getTypeDisplayName("int")).equals("int");
expect(getTypeDisplayName("int?")).equals("int?");
expect(getTypeDisplayName("int?[]")).equals("int?[]");
expect(getTypeDisplayName("Car")).equals("Car");
expect(getTypeDisplayName({ type: "int" })).equals("int");
expect(getTypeDisplayName({ type: "list", objectType: "int" })).equals("int[]");
expect(getTypeDisplayName({ type: "list", objectType: "int", optional: true })).equals("int?[]");
expect(getTypeDisplayName({ type: "dictionary", objectType: "int" })).equals("int{}");
expect(getTypeDisplayName({ type: "set", objectType: "int" })).equals("int<>");
expect(getTypeDisplayName({ type: "object", objectType: "Car" })).equals("Car");
expect(getTypeDisplayName({ type: "object", objectType: "Car", optional: true })).equals("Car?");
});
});
});
Loading