Skip to content

feat/labs migration - #1968

Open
alanpeixinho wants to merge 10 commits into
kernelci:mainfrom
profusion:feat/labs-migration
Open

feat/labs migration#1968
alanpeixinho wants to merge 10 commits into
kernelci:mainfrom
profusion:feat/labs-migration

Conversation

@alanpeixinho

@alanpeixinho alanpeixinho commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates all read paths for lab information from JSONB misc fields (builds.misc->>'lab',
tests.misc->>'runtime') to the new labs table via lab_id foreign key, with JSONB fallback for rows not yet backfilled.
Every SQL query and Python helper that previously extracted lab names by parsing JSONB now uses COALESCE(labs.name, misc_fallback) through a LEFT JOIN on the labs table. This ensures:

  • New data (with lab_id populated by the ingester) reads from the structured FK
  • Historical data (without lab_id) still works via the JSONB fallback
  • After a full backfill, the JSONB fallbacks can be removed (all marked with TODO comments)

How to test

legacy database

  • Use a database where lab_id is NULL on existing rows
  • Verify all pages display lab names as before:
    • Tree details page (boots/tests tabs) — lab column in test history
    • Tree commits history page — build lab and test lab in filters and rows
    • Hardware details page — lab in test/build summaries, history, and filters
    • Build details page — lab column in test list
    • Issue details page — lab column in test list
    • Notifications/metrics endpoint — lab summary counts

Migrated database (test in a local database)

  • Run the migrations available
  • Run the ingester (which already fills lab_id)
    • Verify all pages display lab names as before:
    • Tree details page (boots/tests tabs) — lab column in test history
    • Tree commits history page — build lab and test lab in filters and rows
    • Hardware details page — lab in test/build summaries, history, and filters
    • Build details page — lab column in test list
    • Issue details page — lab column in test list
    • Notifications/metrics endpoint — lab summary counts

@alanpeixinho
alanpeixinho marked this pull request as draft July 1, 2026 20:59
@alanpeixinho alanpeixinho changed the title feat/labs migration {feat/labs migration Jul 1, 2026
@alanpeixinho alanpeixinho changed the title {feat/labs migration [WIP] feat/labs migration Jul 1, 2026
@alanpeixinho
alanpeixinho force-pushed the feat/labs-migration branch from 7ee4011 to 80d7ce6 Compare July 2, 2026 20:51
@alanpeixinho
alanpeixinho marked this pull request as ready for review July 2, 2026 20:53
@alanpeixinho
alanpeixinho force-pushed the feat/labs-migration branch from 80d7ce6 to 3404f84 Compare July 2, 2026 21:16
@alanpeixinho alanpeixinho changed the title [WIP] feat/labs migration feat/labs migration Jul 2, 2026


def assign_lab_ids(builds_buf: list[Builds], tests_buf: list[Tests]) -> None:
"""Resolve each instance's real lab name to a labs.id and set its lab_id FK.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the lab name is unique in the database, why not use that as a primary key? In that case you'd make a first query to check which labs are not in the database yet, a second query to update the table if needed, but you wouldn't need the third query to get the id of the newly added labs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mostly to avoid string keys, since this is an internal key, we might benefit more from integer indices.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Makes sense. I am worried that we are adding one query here, one query there and soon we will have a bloat of unnecessary queries in the ingester, but it's fine for now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is a valid concern. If we plain to move some operations to ingestion time, we certainly are going to end up increasing "ingestion complexity". But I believe that, as long as we keep the ingester fast enough, simplifying the analysis step should be the goal.

tests.number_value AS tests_number_value,
tests.misc AS tests_misc,
tests.environment_compatible AS tests_environment_compatible,
COALESCE(test_labs.name, tests.misc ->> 'runtime') AS tests_lab,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think you forgot a TODO here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread backend/kernelCI_app/queries/build.py Outdated
)
return list(result)
tests = []
for test in result:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not assign directly to lab like before?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Mostly because lab is now the column name, but thinking again. I might change the column name for lab_id, this way we keep the lab name free to use, and follow more closely the the foreign key nomenclature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed mind, to really avoid rename hacking on the ORM, it was easier to just add a proper sql query instead.

result = []
for row in rows:
build_misc = row[11]
sanitized_build_misc = sanitize_dict(build_misc)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why does this not use the fallback?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread backend/kernelCI_app/models.py Outdated
log_excerpt = models.CharField(max_length=16384, blank=True, null=True)
misc = models.JSONField(blank=True, null=True)
lab = models.ForeignKey(
Labs, db_constraint=False, null=True, on_delete=models.DO_NOTHING

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't we use db_constraint=True?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto for Tests

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see all other tables are using db_constraint=False, so there must be a good reason for this, but I do not see it documented

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For the kci keys, we unfortunately have some missing keys in a few rows. But since lab has only internal keys, I believe we can safely enforce constraints on them. Good point.

Comment on lines +454 to +457
build_lab_summary = builds_summary.labs.get(lab)
if not build_lab_summary:
build_lab_summary = StatusCount()
builds_summary.labs[lab] = build_lab_summary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy pattern from previous chunk for consistence and readability

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The point is, this is the original implementation (pre-refactor)

    misc = sanitize_dict(build.misc) or {}
    lab = misc.get("lab", UNKNOWN_STRING)
    if lab:
        build_lab_summary = builds_summary.labs.get(lab)
        if not build_lab_summary:
            build_lab_summary = StatusCount()
            builds_summary.labs[lab] = build_lab_summary
        setattr(
            builds_summary.labs[lab],
            status_key,
            getattr(builds_summary.labs[lab], status_key) + 1,
        )

The conditional for lab is never false, because we are assigning UNKNOWN_STRING for lab.
However, it seems that this function is no longer used, and might be a legacy function used before performance improvements on HardwareDetails endpoints.
I will confirm it, and if this is the case, remove it.
We might as well plan to perform some dead code elimination, and check for similar cases.

@MarceloRobert MarceloRobert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Haven't tested yet, but looks good so far

Comment thread backend/kernelCI_app/queries/build.py Outdated
from typing import Optional

from django.db.models.expressions import F
from django.db import connection

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

very nit: prefer connections['default']

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Part of kernelci#1948

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Part of kernelci#1948

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
    * For analysis queries we are going for lab column information
      first, and coalescing to json misc information.
    *  All COALESCE expressions are marked with TODO comments for removal
      after the lab_id backfill is complete.

    Closes kernelci#1948

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
@alanpeixinho
alanpeixinho force-pushed the feat/labs-migration branch from e0d17ed to 3f30f62 Compare July 15, 2026 18:51
instance.unfiltered_labs["build"].add(build_misc.get("lab", UNKNOWN_STRING))
instance.unfiltered_labs["build"].add(
row_data.get("build_lab") or UNKNOWN_STRING
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

here the code we talked about. Not sure if this conditional should be removed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one is tricky.
Post-migration we no longer read build_misc, so we can't distinguish "no misc at all" from "misc present but no lab" — we only have the lab field. And it's odd to branch on how lab is missing.
I think we should standardize: any missing lab as UNKNOWN.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If we do find a reason to treat them differently, we should include an explicit rule on this.

SELECT
t.misc->>'runtime' AS lab,
-- TODO remove misc->>'runtime' fallback after lab backfill
COALESCE(l.name, t.misc->>'runtime', t.origin) AS lab,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why t.origin here ?
If we have neither a laboratory nor a runtime, won't the WHERE clause you wrote will filter out the record?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nice catch. Missed removing some test here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Rename Builds/Tests FK field from lab to lab_id so lab is free for
annotated lab names without conflicting with the ORM relation.

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Keep lab as the standard Django FK field and resolve build test lab names
via raw SQL, matching the hardware query pattern.

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Enforce the lab FK db_constraint on builds and tests, drop the unused
lab_id from the build tests response, and fix the tree query lab TODO.

Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Signed-off-by: Alan Peixinho <alan.peixinho@profusion.mobi>
Comment on lines +194 to +224
def assign_lab_ids(builds_buf: list[Builds], tests_buf: list[Tests]) -> None:
"""Resolve each instance's real lab name to a labs.id and set its lab_id FK.

Select-first so we only INSERT genuinely new labs (avoids burning the id
sequence on every flush). New labs are committed outside the fact-insert
transaction (autocommit).
"""
objs = [*builds_buf, *tests_buf]
names = {name for obj in objs if (name := obj._lab_name)}

id_map: dict[str, int] = {}
if names:
with connections["default"].cursor() as cursor:
cursor.execute(
"SELECT id, name FROM labs WHERE name = ANY(%s)", [list(names)]
)
id_map = {name: lab_id for lab_id, name in cursor.fetchall()}

missing = [name for name in names if name not in id_map]
if missing:
cursor.executemany(
"INSERT INTO labs (name) VALUES (%s) ON CONFLICT (name) DO NOTHING",
[(name,) for name in missing],
)
cursor.execute(
"SELECT id, name FROM labs WHERE name = ANY(%s)", [missing]
)
id_map.update({name: lab_id for lab_id, name in cursor.fetchall()})

for obj in objs:
obj.lab_id = id_map.get(obj._lab_name) if obj._lab_name else None

@tales-aparecida tales-aparecida Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I was a bit concerned with the 3 queries, so I've asked gemini to try to fold them into a single query, please review

Suggested change
def assign_lab_ids(builds_buf: list[Builds], tests_buf: list[Tests]) -> None:
"""Resolve each instance's real lab name to a labs.id and set its lab_id FK.
Select-first so we only INSERT genuinely new labs (avoids burning the id
sequence on every flush). New labs are committed outside the fact-insert
transaction (autocommit).
"""
objs = [*builds_buf, *tests_buf]
names = {name for obj in objs if (name := obj._lab_name)}
id_map: dict[str, int] = {}
if names:
with connections["default"].cursor() as cursor:
cursor.execute(
"SELECT id, name FROM labs WHERE name = ANY(%s)", [list(names)]
)
id_map = {name: lab_id for lab_id, name in cursor.fetchall()}
missing = [name for name in names if name not in id_map]
if missing:
cursor.executemany(
"INSERT INTO labs (name) VALUES (%s) ON CONFLICT (name) DO NOTHING",
[(name,) for name in missing],
)
cursor.execute(
"SELECT id, name FROM labs WHERE name = ANY(%s)", [missing]
)
id_map.update({name: lab_id for lab_id, name in cursor.fetchall()})
for obj in objs:
obj.lab_id = id_map.get(obj._lab_name) if obj._lab_name else None
def assign_lab_ids(builds_buf: list[Builds], tests_buf: list[Tests]) -> None:
"""Resolve each instance's real lab name to a labs.id and set its lab_id FK.
Uses a single optimized CTE join to insert missing records and fetch all IDs
in 1 round-trip without sequence waste or ORM overhead.
"""
objs = [*builds_buf, *tests_buf]
names = list({obj._lab_name for obj in objs if getattr(obj, "_lab_name", None)})
if not names:
for obj in objs:
obj.lab_id = None
return
query = """
WITH input_names AS (
-- 1. Unnest and deduplicate inputs in Postgres C-memory
SELECT DISTINCT unnest(%s::text[]) AS name
),
inserted AS (
-- 2. Anti-join via LEFT JOIN / IS NULL (Faster than NOT EXISTS)
INSERT INTO labs (name)
SELECT i.name
FROM input_names i
LEFT JOIN labs l ON l.name = i.name
WHERE l.name IS NULL
RETURNING id, name
)
-- 3. Combine newly inserted IDs with existing IDs
SELECT id, name FROM inserted
UNION ALL
SELECT l.id, l.name
FROM labs l
JOIN input_names i ON l.name = i.name;
"""
with connections["default"].cursor() as cursor:
cursor.execute(query, [names])
# Unpacks (id, name) tuples into a {name: id} dictionary directly
id_map = dict(cursor.fetchall())
for obj in objs:
lab_name = getattr(obj, "_lab_name", None)
obj.lab_id = id_map.get(lab_name) if lab_name else None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

great optimization but I think it might burn the id sequence in some cases, right? which is the concern of the original approach.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actually, it doesn't...

but it's great that you mentioned that! We still need need ON CONFLICT (name) DO NOTHING like we have in the original code to avoid the race condition.

Only when the race condition happens there will be ID burning on both the original and using the single query

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is tricky, because in the original solution, despite having tree queries, only the first simpler query would hit most of the time (since we expect to have the number of labs being significantly smaller than the number of builds or tests ).
With the unified query we are running 100% of the time a more complex query (I will take a look how this impact performance).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

On the topic of race condition (thanks for catching that), I believe this can be solved with a lock in the solution with split queries.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was reviewing this PR again, and realized that we are in fact safe from race condition here.
The do nothing on conflict seems to really be enough.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The do nothing on conflict seems to really be enough.

Oh yes, sorry if I was not clear! My point was that including the DO NOTHING in my suggestion would prevent the race condition, like it is preventing it in the original code

@tales-aparecida

Copy link
Copy Markdown

I'm concerned with how much overhead the labs will bring to the kcidb ingestion. either put it under a feature flag, so we can toggle it off quickly in case it's catastrophic, or show some metrics comparing the time to consume a few hundred payloads in a local development, before and after this MR

@alanpeixinho

Copy link
Copy Markdown
Contributor Author

@tales-aparecida, (checking in a local run) the new version turned out to be slightly faster (but it could be just noise).
But anyway, I believe we should have comparable performance with the changes made here.

Previous implementation

Metric Value
Progress samples 169
Min files/s 145.8
Max files/s 612.1
Avg files/s 167.8
Last progress files/s 147.5
Final ingest files/s 142.82
Final ingest elapsed (s) 350.09

New implementation

Metric Value
Progress samples 167
Min files/s 149.0
Max files/s 590.6
Avg files/s 182.9
Last progress files/s 149.1
Final ingest files/s 144.69
Final ingest elapsed (s) 345.56

Hardware

Component Details
CPU Intel Core 7 250U, x86_64
CPU topology 1 socket, 10 cores, 12 logical CPUs
CPU frequency 400 MHz minimum, up to 5.4 GHz reported by lscpu; boost enabled
CPU scaling intel_pstate, powersave governor, balance_performance preference
CPU cache L1d 352 KiB, L1i 576 KiB, L2 6.5 MiB, L3 12 MiB
Memory 31.9 GiB online, 8 GiB swap
Storage ADATA SM2P41D3Q 512 GB NVMe, 476.9 GiB usable
Storage stack NVMe → LUKS encryption → LVM → ext4

Software

Component Details
OS Ubuntu 26.04 LTS (Resolute Raccoon)
Kernel Linux 7.0.0-28-generic, x86_64
C library glibc 2.43
Python 3.12.13
Django 5.2.11
psycopg 3.2.5

Comparison table

# old elapsed (s) old done old files/s new elapsed (s) new done new files/s Δ files/s
1 2.09 1280/50000 612.1 2.10 1238/50000 590.6 -21.5
2 4.09 1600/50000 391.1 4.10 1500/50000 366.1 -25.0
3 6.09 1600/50000 262.6 6.10 1806/50000 296.2 +33.6
4 8.09 1940/50000 239.7 8.10 2434/50000 300.6 +60.9
5 10.09 2274/50000 225.3 10.10 2937/50000 290.9 +65.6
6 12.09 2914/50000 241.0 12.10 3180/50000 262.9 +21.9
7 14.09 3333/50000 236.5 14.10 3884/50000 275.5 +39.0
8 16.09 3597/50000 223.5 16.10 4293/50000 266.7 +43.2
9 18.09 3991/50000 220.6 18.10 4800/50000 265.2 +44.6
10 20.09 4276/50000 212.8 20.10 4967/50000 247.1 +34.3
11 22.09 4934/50000 223.3 22.10 5334/50000 241.4 +18.1
12 24.10 5130/50000 212.9 24.10 5774/50000 239.6 +26.7
13 26.10 5663/50000 217.0 26.10 6378/50000 244.4 +27.4
14 28.10 6203/50000 220.8 28.10 6773/50000 241.0 +20.2
15 30.10 6400/50000 212.7 30.10 7073/50000 235.0 +22.3
16 32.10 6656/50000 207.4 32.10 7549/50000 235.2 +27.8
17 34.10 7185/50000 210.7 34.10 7976/50000 233.9 +23.2
18 36.10 7500/50000 207.8 36.10 8256/50000 228.7 +20.9
19 38.10 7611/50000 199.8 38.10 8578/50000 225.1 +25.3
20 40.10 8017/50000 199.9 40.10 9120/50000 227.4 +27.5
21 42.10 8190/50000 194.5 42.10 9663/50000 229.5 +35.0
22 44.10 8718/50000 197.7 44.10 9900/50000 224.5 +26.8
23 46.10 9112/50000 197.7 46.10 10146/50000 220.1 +22.4
24 48.10 9263/50000 192.6 48.10 10420/50000 216.6 +24.0
25 50.10 9512/50000 189.9 50.10 11120/50000 221.9 +32.0
26 52.10 10062/50000 193.1 52.10 11488/50000 220.5 +27.4
27 54.10 10328/50000 190.9 54.10 11538/50000 213.3 +22.4
28 56.10 10629/50000 189.5 56.10 11950/50000 213.0 +23.5
29 58.10 10800/50000 185.9 58.11 12297/50000 211.6 +25.7
30 60.10 10961/50000 182.4 60.11 12658/50000 210.6 +28.2
31 62.10 11112/50000 178.9 62.11 13191/50000 212.4 +33.5
32 64.10 11526/50000 179.8 64.11 13669/50000 213.2 +33.4
33 66.10 11673/50000 176.6 66.11 14017/50000 212.0 +35.4
34 68.10 11928/50000 175.1 68.11 14490/50000 212.8 +37.7
35 70.10 12059/50000 172.0 70.11 14926/50000 212.9 +40.9
36 72.10 12184/50000 169.0 72.11 15178/50000 210.5 +41.5
37 74.10 12681/50000 171.1 74.11 15585/50000 210.3 +39.2
38 76.10 13331/50000 175.2 76.11 15925/50000 209.2 +34.0
39 78.10 13477/50000 172.6 78.11 16243/50000 208.0 +35.4
40 80.10 13846/50000 172.8 80.11 16545/50000 206.5 +33.7
41 82.11 14158/50000 172.4 82.11 16730/50000 203.8 +31.4
42 84.11 14379/50000 171.0 84.11 17007/50000 202.2 +31.2
43 86.11 14734/50000 171.1 86.11 17303/50000 200.9 +29.8
44 88.11 15149/50000 171.9 88.11 17400/50000 197.5 +25.6
45 90.11 15352/50000 170.4 90.11 17534/50000 194.6 +24.2
46 92.11 15679/50000 170.2 92.11 17825/50000 193.5 +23.3
47 94.11 15982/50000 169.8 94.11 18068/50000 192.0 +22.2
48 96.11 16402/50000 170.7 96.11 18650/50000 194.0 +23.3
49 98.11 16500/50000 168.2 98.11 18851/50000 192.1 +23.9
50 100.11 16702/50000 166.8 100.11 19005/50000 189.8 +23.0
51 102.11 16900/50000 165.5 102.11 19100/50000 187.0 +21.5
52 104.11 17087/50000 164.1 104.11 19425/50000 186.6 +22.5
53 106.11 17245/50000 162.5 106.11 19760/50000 186.2 +23.7
54 108.11 17373/50000 160.7 108.11 20028/50000 185.2 +24.5
55 110.11 17668/50000 160.5 110.11 20225/50000 183.7 +23.2
56 112.11 18042/50000 160.9 112.11 20613/50000 183.9 +23.0
57 114.11 18429/50000 161.5 114.12 20998/50000 184.0 +22.5
58 116.11 18797/50000 161.9 116.12 21391/50000 184.2 +22.3
59 118.11 18800/50000 159.2 118.12 21500/50000 182.0 +22.8
60 120.11 19049/50000 158.6 120.12 21606/50000 179.9 +21.3
61 122.11 19374/50000 158.7 122.12 21854/50000 179.0 +20.3
62 124.11 19565/50000 157.6 124.12 21986/50000 177.1 +19.5
63 126.11 19932/50000 158.0 126.12 22223/50000 176.2 +18.2
64 128.11 20342/50000 158.8 128.12 22756/50000 177.6 +18.8
65 130.11 20604/50000 158.4 130.12 23026/50000 177.0 +18.6
66 132.11 20887/50000 158.1 132.12 23315/50000 176.5 +18.4
67 134.11 21161/50000 157.8 134.12 23618/50000 176.1 +18.3
68 136.11 21471/50000 157.7 136.12 23835/50000 175.1 +17.4
69 138.12 21831/50000 158.1 138.12 24200/50000 175.2 +17.1
70 140.12 22174/50000 158.3 140.12 24337/50000 173.7 +15.4
71 142.12 22556/50000 158.7 142.12 24443/50000 172.0 +13.3
72 144.12 22934/50000 159.1 144.12 24660/50000 171.1 +12.0
73 146.12 23294/50000 159.4 146.12 25013/50000 171.2 +11.8
74 148.12 23414/50000 158.1 148.12 25226/50000 170.3 +12.2
75 150.12 23751/50000 158.2 150.12 25383/50000 169.1 +10.9
76 152.12 24100/50000 158.4 152.12 25641/50000 168.6 +10.2
77 154.12 24242/50000 157.3 154.12 25853/50000 167.7 +10.4
78 156.12 24443/50000 156.6 156.12 26105/50000 167.2 +10.6
79 158.12 24843/50000 157.1 158.12 26349/50000 166.6 +9.5
80 160.12 25120/50000 156.9 160.12 26669/50000 166.6 +9.7
81 162.12 25227/50000 155.6 162.12 26797/50000 165.3 +9.7
82 164.12 25300/50000 154.2 164.13 26824/50000 163.4 +9.2
83 166.12 25486/50000 153.4 166.13 27256/50000 164.1 +10.7
84 168.12 25816/50000 153.6 168.13 27814/50000 165.4 +11.8
85 170.12 26214/50000 154.1 170.13 28019/50000 164.7 +10.6
86 172.12 26300/50000 152.8 172.13 28411/50000 165.1 +12.3
87 174.12 26500/50000 152.2 174.13 28780/50000 165.3 +13.1
88 176.12 26888/50000 152.7 176.13 28841/50000 163.8 +11.1
89 178.12 27108/50000 152.2 178.13 29110/50000 163.4 +11.2
90 180.12 27608/50000 153.3 180.13 29498/50000 163.8 +10.5
91 182.12 27837/50000 152.8 182.13 29700/50000 163.1 +10.3
92 184.12 27900/50000 151.5 184.13 29916/50000 162.5 +11.0
93 186.12 28135/50000 151.2 186.13 30229/50000 162.4 +11.2
94 188.12 28594/50000 152.0 188.13 30436/50000 161.8 +9.8
95 190.13 29116/50000 153.1 190.13 30663/50000 161.3 +8.2
96 192.13 29308/50000 152.5 192.13 30982/50000 161.3 +8.8
97 194.13 29445/50000 151.7 194.13 31289/50000 161.2 +9.5
98 196.13 29770/50000 151.8 196.13 31430/50000 160.3 +8.5
99 198.13 30228/50000 152.6 198.13 31576/50000 159.4 +6.8
100 200.13 30659/50000 153.2 200.13 31750/50000 158.6 +5.4
101 202.13 30700/50000 151.9 202.13 32033/50000 158.5 +6.6
102 204.13 30890/50000 151.3 204.13 32294/50000 158.2 +6.9
103 206.13 31146/50000 151.1 206.13 32572/50000 158.0 +6.9
104 208.13 31500/50000 151.3 208.13 32822/50000 157.7 +6.4
105 210.13 31680/50000 150.8 210.13 33236/50000 158.2 +7.4
106 212.13 31863/50000 150.2 212.13 33463/50000 157.7 +7.5
107 214.13 32094/50000 149.9 214.13 33600/50000 156.9 +7.0
108 216.13 32434/50000 150.1 216.13 33834/50000 156.5 +6.4
109 218.13 32725/50000 150.0 218.13 34009/50000 155.9 +5.9
110 220.13 33071/50000 150.2 220.14 34243/50000 155.6 +5.4
111 222.13 33375/50000 150.2 222.14 34596/50000 155.7 +5.5
112 224.13 33622/50000 150.0 224.14 34846/50000 155.5 +5.5
113 226.13 33700/50000 149.0 226.14 35177/50000 155.6 +6.6
114 228.13 33780/50000 148.1 228.14 35450/50000 155.4 +7.3
115 230.13 34232/50000 148.7 230.14 35826/50000 155.7 +7.0
116 232.13 34525/50000 148.7 232.14 35910/50000 154.7 +6.0
117 234.13 34761/50000 148.5 234.14 36088/50000 154.1 +5.6
118 236.13 34838/50000 147.5 236.14 36486/50000 154.5 +7.0
119 238.13 35234/50000 148.0 238.14 37041/50000 155.5 +7.5
120 240.13 35744/50000 148.9 240.14 37100/50000 154.5 +5.6
121 242.13 35900/50000 148.3 242.14 37162/50000 153.5 +5.2
122 244.13 35993/50000 147.4 244.14 37500/50000 153.6 +6.2
123 246.14 36159/50000 146.9 246.14 37650/50000 153.0 +6.1
124 248.14 36537/50000 147.2 248.14 37828/50000 152.4 +5.2
125 250.14 36923/50000 147.6 250.14 38049/50000 152.1 +4.5
126 252.14 37245/50000 147.7 252.14 38589/50000 153.0 +5.3
127 254.14 37336/50000 146.9 254.14 39079/50000 153.8 +6.9
128 256.14 37623/50000 146.9 256.14 39101/50000 152.7 +5.8
129 258.14 37957/50000 147.0 258.14 39266/50000 152.1 +5.1
130 260.14 38222/50000 146.9 260.14 39409/50000 151.5 +4.6
131 262.14 38456/50000 146.7 262.14 39797/50000 151.8 +5.1
132 264.14 38751/50000 146.7 264.14 40428/50000 153.1 +6.4
133 266.14 39308/50000 147.7 266.14 40518/50000 152.2 +4.5
134 268.14 39531/50000 147.4 268.14 40722/50000 151.9 +4.5
135 270.14 39700/50000 147.0 270.14 40861/50000 151.3 +4.3
136 272.14 39713/50000 145.9 272.14 41150/50000 151.2 +5.3
137 274.14 40167/50000 146.5 274.14 41538/50000 151.5 +5.0
138 276.14 40590/50000 147.0 276.15 41937/50000 151.9 +4.9
139 278.14 40872/50000 146.9 278.15 42314/50000 152.1 +5.2
140 280.14 41098/50000 146.7 280.15 42517/50000 151.8 +5.1
141 282.14 41200/50000 146.0 282.15 42639/50000 151.1 +5.1
142 284.14 41481/50000 146.0 284.15 43100/50000 151.7 +5.7
143 286.14 41890/50000 146.4 286.15 43210/50000 151.0 +4.6
144 288.14 42205/50000 146.5 288.15 43470/50000 150.9 +4.4
145 290.14 42676/50000 147.1 290.15 43798/50000 151.0 +3.9
146 292.14 42920/50000 146.9 292.15 44013/50000 150.7 +3.8
147 294.14 43226/50000 147.0 294.15 44268/50000 150.5 +3.5
148 296.15 43401/50000 146.6 296.15 44653/50000 150.8 +4.2
149 298.15 43702/50000 146.6 298.15 44812/50000 150.3 +3.7
150 300.15 44084/50000 146.9 300.15 44989/50000 149.9 +3.0
151 302.15 44278/50000 146.5 302.15 45281/50000 149.9 +3.4
152 304.15 44553/50000 146.5 304.15 45628/50000 150.0 +3.5
153 306.15 44873/50000 146.6 306.15 46089/50000 150.5 +3.9
154 308.15 45006/50000 146.1 308.15 46544/50000 151.0 +4.9
155 310.15 45227/50000 145.8 310.15 46600/50000 150.2 +4.4
156 312.15 45513/50000 145.8 312.15 46709/50000 149.6 +3.8
157 314.15 45919/50000 146.2 314.15 47421/50000 150.9 +4.7
158 316.15 46405/50000 146.8 316.17 47762/50000 151.1 +4.3
159 318.15 46589/50000 146.4 318.17 48041/50000 151.0 +4.6
160 320.15 47026/50000 146.9 320.17 48109/50000 150.3 +3.4
161 322.15 47791/50000 148.4 322.17 48245/50000 149.7 +1.3
162 324.15 48041/50000 148.2 324.17 48416/50000 149.4 +1.2
163 326.15 48198/50000 147.8 326.17 48924/50000 150.0 +2.2
164 328.15 48361/50000 147.4 328.17 49043/50000 149.4 +2.0
165 330.15 48678/50000 147.4 330.17 49211/50000 149.0 +1.6
166 332.15 49032/50000 147.6 332.17 49533/50000 149.1 +1.5
167 334.15 49396/50000 147.8 334.17 49822/50000 149.1 +1.3
168 336.15 49628/50000 147.6
169 338.15 49889/50000 147.5

@tales-aparecida

Copy link
Copy Markdown

@tales-aparecida, (checking in a local run) the new version turned out to be slightly faster (but it could be just noise). But anyway, I believe we should have comparable performance with the changes made here.

I'm confused, is "old" the main branch and "new" the feature branch?
I'm a bit impressed it didn't impact the ingestion time.

@tales-aparecida

Copy link
Copy Markdown

Please autosquash the fixups 😁

@alanpeixinho

Copy link
Copy Markdown
Contributor Author

@tales-aparecida, (checking in a local run) the new version turned out to be slightly faster (but it could be just noise). But anyway, I believe we should have comparable performance with the changes made here.

I'm confused, is "old" the main branch and "new" the feature branch? I'm a bit impressed it didn't impact the ingestion time.

Exactly. Sorry for the bad nomenclature.
But regarding performance.
We only reach database for reads if the information is not available in memory, so it should reach it lab roughly once per worker.
And the write paths should hit even less, as only one worker is expected to hit a missing lab.

@tales-aparecida

Copy link
Copy Markdown

regarding performance. We only reach database for reads if the information is not available in memory, so it should reach it lab roughly once per worker. And the write paths should hit even less, as only one worker is expected to hit a missing lab.

which layer of cache is that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants