5454 ("intel" , "List_of_Intel_graphics_processing_units" , "Intel Graphics" ),
5555]
5656
57- _BRAND_DISPLAY : dict [str , str ] = {"nvidia" : "NVIDIA" , "amd" : "AMD" , "ati" : "ATI" , "intel" : "Intel" }
58-
5957# The dataset keeps ATI-branded boards under ``ati``; AMD retired the ATI brand
6058# in August 2010 and the curated records switch to ``amd`` from October 2010.
6159_ATI_BRAND_END = date (2010 , 10 , 1 )
6967 "DDR5" , "DDR4" , "DDR3" , "DDR2" , "DDR" , "SDRAM" , "SDR" ,
7068)
7169_MEMORY_TYPE_DISPLAY = {"HBM2E" : "HBM2e" , "HBM3E" : "HBM3e" }
70+ # Types the curated records spell their own way ("SGRAM", "EDO DRAM"): a cell
71+ # naming one of them states no type from MEMORY_TYPES.
72+ _OTHER_MEMORY_RE = re .compile (r"(?<![A-Z0-9])(?:SGRAM|EDO|VRAM|WRAM|FPM|DRAM)(?![A-Z0-9])" )
7273
7374_NUMBER_RE = re .compile (r"\d[\d,]*(?:\.\d+)?" )
7475_RANGE_RE = re .compile (r"(\d[\d,]*(?:\.\d+)?)\s*(?:–|—|-|to)\s*(\d[\d,]*(?:\.\d+)?)" )
7576_FOOTNOTE_RE = re .compile (r"\s*\[[^\]]{1,12}\]" )
7677_TRAILING_PAREN_RE = re .compile (r"\s*\([^)]*\)\s*$" )
7778_MULTI_GPU_RE = re .compile (r"\d\s*[×x]\s*\d" )
7879_BUS_RE = re .compile (r"\b(PCIe|PCI-E|PCI Express|AGP|PCI|MXM(?:-[A-Z]+)?)\b[^/,;]*" , re .IGNORECASE )
79- _BUS_NAME_RE = re .compile (r"\b(PCIe|AGP|PCI|MXM)\b" , re .IGNORECASE )
80+ _BUS_NAME_RE = re .compile (r"\b(PCIe|AGP|PCI|MXM|ISA|EISA|VLB|VL-Bus|MCA )\b" , re .IGNORECASE )
8081# Integrated/chipset graphics are out of scope for the discrete-GPU table.
8182_OUT_OF_SCOPE_RE = re .compile (r"\bIGP\b|integrated|on-?die|\bAPU\b|nForce" , re .IGNORECASE )
8283# Chipset IGPs: a memory cell naming only system memory ("Up to 256 from system
9394 r"\b(?:mobile|mobility|laptop|notebook|max-q|go)\b|\b[a-z]?\d{2,5}m[a-z]*\b|\bm\d{3,4}|\bmx\s?\d" ,
9495 re .IGNORECASE ,
9596)
97+ _LAPTOP_TIER_RE = re .compile (r"\b(?:mobile|laptop|notebook)\b" )
9698_BRAND_WORD_RE = re .compile (r"\b(?:geforce|radeon|quadro|firepro|firegl|tesla)\b" , re .IGNORECASE )
9799# "Clock Rate / Base (Boost) ( MHz )": "1291 (1392)" is base 1291, boost 1392.
98100_BASE_BOOST_RE = re .compile (r"\b(?:base|core)\b[^/]*\(\s*boost|\bbase boost\b" )
128130 (r"NV2\d" , "Kelvin" ),
129131 (r"NV3\d" , "Rankine" ),
130132 (r"NV4\d|G7\d" , "Curie" ),
131- (r"G8\d|G9\d|GT2\d\d" , "Tesla" ),
133+ # Curated records name the second generations (GT200, GF11x, GK2xx) per
134+ # chip; the versioned entries come before the generic ones.
135+ (r"GT2\d\d" , "Tesla 2.0" ),
136+ (r"G8\d|G9\d" , "Tesla" ),
137+ (r"GF11\d" , "Fermi 2.0" ),
132138 (r"GF1\d\d" , "Fermi" ),
139+ (r"GK2\d\d" , "Kepler 2.0" ),
133140 (r"GK\d" , "Kepler" ),
134141 (r"GM\d" , "Maxwell" ),
135142 (r"GP\d" , "Pascal" ),
@@ -269,6 +276,8 @@ def _memory_gb(text: str, unit: str) -> float | None:
269276def _memory_type (text : str ) -> str | None :
270277 """The memory type a cell names; ``None`` when it names several."""
271278 upper = text .upper ()
279+ if _OTHER_MEMORY_RE .search (upper ):
280+ return None
272281 kinds = [
273282 kind
274283 for kind in MEMORY_TYPES
@@ -279,9 +288,16 @@ def _memory_type(text: str) -> str | None:
279288
280289def _release_period (text : str ) -> tuple [date , date ] | None :
281290 """The release period a cell names; ``None`` for several dates or a ``?``."""
282- cleaned = _FOOTNOTE_RE .sub ("" , text )
283- if "?" in cleaned :
291+ if "?" in text :
284292 return None
293+ periods = _cell_periods (text )
294+ return periods .pop () if len (periods ) == 1 else None
295+
296+
297+ def _cell_periods (text : str ) -> set [tuple [date , date ]]:
298+ """Every date period a cell names: ``"May 1, 2007 (PCIe) October 1, 2007 (AGP)"``
299+ names two, ``"2004?"`` one."""
300+ cleaned = _FOOTNOTE_RE .sub ("" , text )
285301 taken : list [tuple [int , int ]] = []
286302 periods : set [tuple [date , date ]] = set ()
287303 for pattern in _DATE_IN_CELL_RES :
@@ -291,7 +307,7 @@ def _release_period(text: str) -> tuple[date, date] | None:
291307 taken .append (match .span ())
292308 if (period := parse_date_period (match .group (0 ))) is not None :
293309 periods .add (period )
294- return periods . pop () if len ( periods ) == 1 else None
310+ return periods
295311
296312
297313def normalize_bus_interface (text : str ) -> str | None :
@@ -311,6 +327,9 @@ def normalize_bus_interface(text: str) -> str | None:
311327 if not match :
312328 return None
313329 if match .group (1 ).lower () != "pcie" :
330+ # "AGP 4x,8x": board variants again.
331+ if len (set (re .findall (r"(\d+)\s*x\b" , cleaned [match .start () :]))) > 1 :
332+ return None
314333 value = match .group (0 )
315334 value = re .sub (r"\s+x\s*(\d+)" , r" x\1" , value )
316335 value = re .sub (r"(\d)\s*x\b" , r"\1x" , value )
@@ -418,18 +437,29 @@ def unit(key: str) -> str:
418437 # "2× 128": per-GPU values on dual-GPU boards don't fit one record.
419438 return None
420439 problems : tuple [str , ...] = ()
421- if headings and headings [- 1 ].lower ().startswith ("mobile" ) and not _LAPTOP_MARKER_RE .search (
422- raw_model
423- ):
440+ laptop_table = bool (headings ) and headings [- 1 ].lower ().startswith ("mobile" )
441+ if laptop_table and not _LAPTOP_MARKER_RE .search (raw_model ):
424442 problems = ("laptop table row without a laptop marker in its name" ,)
425443
426444 release_period = _release_period (text ("release_date" ))
427445 release_date = release_date_of (release_period )
428- if manufacturer == "amd" and release_period is not None and release_period [1 ] < _ATI_BRAND_END :
446+ # Before the rebrand by every date the cell names ("2004?", "May 1, 2007
447+ # (PCIe) October 1, 2007 (AGP)"), even when no one date is the release.
448+ periods = _cell_periods (text ("release_date" ))
449+ if manufacturer == "amd" and periods and all (last < _ATI_BRAND_END for _ , last in periods ):
429450 manufacturer = "ati"
430451 slug = slugify (model , manufacturer = manufacturer )
431452 if len (slug ) < 4 or not any (ch .isdigit () for ch in slug ):
432453 return None
454+ if release_date is None :
455+ # The layout files a board under its release year; without one there
456+ # is no folder to put it in, even as a draft.
457+ problems += ("no release date to file it under" ,)
458+ # "Quadro M5500" in a laptop table is the laptop part, curated as "Quadro
459+ # M5500 Mobile"; dedup checks that name too.
460+ aliases : tuple [str , ...] = ()
461+ if laptop_table and not _LAPTOP_TIER_RE .search (slug ):
462+ aliases = (f"{ slug } -mobile" ,)
433463
434464 base_clock = _clock_mhz (text ("base_clock" ), unit ("base_clock" ))
435465 boost_clock = _clock_mhz (
@@ -467,8 +497,8 @@ def unit(key: str) -> str:
467497 architecture_from_codename (text ("codename" ), manufacturer )
468498 )
469499
470- brand = _BRAND_DISPLAY . get ( manufacturer , manufacturer . title ())
471- name = model if model . lower (). startswith ( manufacturer ) else f" { brand } { model } "
500+ # Dataset GPU names leave the brand to `` manufacturer``: "GeForce GTX 1660 Ti".
501+ name = re . sub ( r"^(?:NVIDIA|AMD|ATI|Intel)\s+" , "" , model , flags = re . IGNORECASE )
472502 record : dict [str , object | None ] = {
473503 "slug" : slug ,
474504 "name" : name ,
@@ -503,4 +533,5 @@ def unit(key: str) -> str:
503533 missing_fields = missing ,
504534 problems = problems ,
505535 released_by = release_period [1 ] if release_period else None ,
536+ aliases = aliases ,
506537 )
0 commit comments