When you read Python code, sooner or later you hit a line like this:
data: Dict[str, int] = {}
The : Dict[str, int] part looks strange the first time. In this post we'll
figure out exactly what that one line means — and whether a "type hint" is actually
enforced — using tiny runnable examples.
1. One line, three things at once
That single line is really three pieces glued together.
data : Dict[str, int] = {}
│ │ │
name type hint actual
(a note) value
Piece
Meaning
data
the variable name
: Dict[str, int]
a type hint — "keys are str, values are int". Just a note for humans/editors
= {}
the actual value = an empty dict
At runtime it is exactly the same as:
data = {} # drop the hint and this is all that's left
2. = {} is just a dict
A dict is a "key → value" store. It has nothing to do with type hints — it's a basic
built-in type that has always existed.
data = {} # empty dict
data["gemm"] = "A" # key (str) -> value
data["conv2d"] = "B"
print(data) # {'gemm': 'A', 'conv2d': 'B'}
print(data["gemm"]) # A
print(list(data)) # ['gemm', 'conv2d']
3. : Dict[str, int] is a "type hint"
Dict[str, int] is a note saying "a dict whose keys are strings and values
are integers". Python does not enforce that note when it runs.
from typing import Dict
ages: Dict[str, int] = {} # at runtime this is just ages = {}
ages["alice"] = 30
ages["bob"] = 25
print(ages) # {'alice': 30, 'bob': 25}
4. Is it really not enforced? — break it on purpose
Violating the hint does not raise an error. Let's prove it.
from typing import Dict
ages: Dict[str, int] = {} # promise: "str keys, int values"
ages["alice"] = 30 # keeps the promise
ages["oops"] = "not-int" # value is a string -> breaks it
ages[123] = 99 # key is an int -> breaks it
print(ages)
Output:
{'alice': 30, 'oops': 'not-int', 123: 99}
Key point: a type hint is not enforced. The Python
interpreter simply ignores it at runtime, so breaking it still runs fine.
5. So why write hints at all?
If they're not enforced, why bother? Because they're a "quality tool", not a rule.
Humans — reading the code, you instantly see "this is a str→int dict".
Editors (IDEs) — autocomplete, and a red squiggle when you misuse it.
Static checkers (mypy) — run mypy file.py separately and it catches
violations before you run the code.
A hint is "a promise + documentation", not a check. To actually catch violations,
run a tool like mypy yourself — the interpreter won't.
6. Dict vs dict — and when did this syntax appear?
The dict itself is old; the type-hint syntax is the newer part.
Syntax
Import needed?
Introduced
Dict[str, int] (capital)
from typing import Dict
Python 3.5 (2015)
dict[str, int] (lowercase)
none (built-in)
Python 3.9 (2020)
dict (plain)
none
always
Annotating a variable with x: int = 0 has been possible since Python 3.6 (2016).
Both forms mean the same thing, so new code usually prefers the lowercase dict[...].
A GPU kernel launch is a hierarchy of work units. Bigger units contain smaller ones.
AMD term
NVIDIA term
What it is
Grid
Grid
The whole kernel launch — covers the entire problem.
Workgroup
Block / threadblock
A group of threads on one Compute Unit (CU). Shares LDS (shared memory). Can synchronize via __syncthreads().
Wavefront (wave)
Warp
64 threads (AMD CDNA) executing the same instruction simultaneously (SIMT).
Thread (work-item)
Thread
One lane in a wave. Has its own thread ID and register state.
GRID (kernel launch — covers the whole problem)
Workgroup 0 (256 threads)
Wave 0 (T0..T63)
Wave 1 (T64..T127)
Wave 2 (T128..T191)
Wave 3 (T192..T255)
Workgroup 1 (256 threads)
Wave 0..3 (64 threads each)
Workgroup N−1
Wave 0..3
Key: 64 threads in a wave always execute the same instruction in lock-step.
That is the essence of SIMT (Single Instruction Multiple Threads).
2. Lane vs thread
"Lane" and "thread" are two views of the same physical execution slot.
Lane = a hardware ALU slot inside a SIMD unit. There are exactly 64 lanes per SIMD on AMD CDNA.
Thread = the software view of one lane. Has its own thread ID and private registers.
One lane runs one thread at a time. They are 1:1 within an executing wave.
1 wave (= 64 threads) running on 1 SIMD:
Lane 0 ↔ Thread 0 (running my_function with tid=0)
Lane 1 ↔ Thread 1 (running my_function with tid=1)
Lane 2 ↔ Thread 2
...
Lane 63 ↔ Thread 63
All 64 lanes execute the same instruction at the same cycle.
3. Hardware: GPU → CU → SIMD → lane
Below the software hierarchy is the physical hardware:
GPU contains many CUs (Compute Units). Example: MI300X has 304 CUs.
CU contains 4 SIMD units. The 4 SIMDs in a CU operate in parallel.
SIMD contains 64 lanes (ALUs) and a register file that can hold up to 8 resident waves.
SIMD ≠ instant execution. A SIMD holds up to 8 waves in its register file but
executes only one wave per cycle. With multiple waves resident, when one wave waits
for memory, the SIMD switches to another. This is latency hiding.
4. Registers, VGPRs & occupancy
Register types
Type
Size
Scope
Notes
VGPR (vector GPR)
32-bit (4 B)
Private per lane
Up to 256 per lane per wave. Each lane sees its own VGPR.
SGPR (scalar GPR)
32-bit (4 B)
Shared by 64 lanes
Used for scalar values like loop counters, addresses.
AGPR (accumulator GPR)
32-bit (4 B)
Private per lane
CDNA-only. Used as MFMA accumulators.
How much register memory does one lane have?
1 lane × 256 VGPRs × 4 bytes = 1 KB per lane
1 wave (64 lanes) × 1 KB = 64 KB total register file used by one wave
Occupancy
Occupancy = number of waves resident on a SIMD (1 to 8). Higher occupancy enables better latency hiding.
If a wave uses 256 VGPRs/lane → only 1 wave fits in SIMD → occupancy 1
If a wave uses 128 VGPRs/lane → 2 waves fit → occupancy 2
If a wave uses 32 VGPRs/lane → 8 waves fit → occupancy 8 (max)
More resident waves = SIMD can switch when one wave stalls on memory.
Trade-off: using more VGPRs per thread means each thread can hold more
data, but fewer waves can be resident, reducing latency hiding.
GPU memory has multiple levels, similar to CPU cache hierarchy:
Level
Size (per CU / total)
Latency (cycles)
Managed by
CPU analogue
Registers (VGPR/SGPR)
~256 KB / CU
~1
Compiler
CPU registers
LDS (shared memory)
64 KB / CU
~10–30
Software (explicit loads/stores)
Scratchpad / fast SRAM
L1 cache
16 KB / CU
~30
Hardware (transparent)
L1 cache
L2 cache
~16 MB total
~150
Hardware
L2 cache
Infinity / L3
~256 MB
~300
Hardware
L3 cache
HBM (global memory)
192 GB
~500–1000
HW + software
DRAM
Key insight: registers are basically free (~1 cycle), HBM is very expensive (~500+ cycles).
Performance comes from staging data through LDS and registers, and from
hiding HBM latency with high occupancy.
6. Kernel launch <<< grid, block >>>
HIP/CUDA kernel launch syntax:
add_kernel<<< grid, block >>>(A, B, C, N);
Parameter
Meaning
Example
block (a.k.a. blockSize)
Threads per workgroup
256 → 4 waves per workgroup
grid
Number of workgroups
4 → 4 workgroups total
(implicit)
Wave count = blockSize / 64
256 / 64 = 4 waves per workgroup
You don't pick the wave count directly — it is derived from blockSize. The hardware always groups threads into waves of 64 on CDNA.
add_kernel<<< grid=4, block=256 >>>(...)
Total threads = 4 × 256 = 1024
Total waves = 1024 / 64 = 16
Total workgroups = 4
Each workgroup → one CU
Each wave → one SIMD inside that CU
7. Vector loads & the 16-byte rule
A single load instruction can pull up to 16 bytes into a thread's registers. This is the hardware limit on AMD CDNA.
The number of elements per load (called vec size) depends on the data type:
Data type
Size (B)
vec=1
vec=2
vec=4
vec=8
vec=16
fp16 / bf16
2
2 B
4 B
8 B
16 B (max)
—
fp32
4
4 B
8 B
16 B (max)
—
—
int8
1
1 B
2 B
4 B
8 B
16 B (max)
Rule:vec × sizeof(dtype) ≤ 16 byte. Larger vec means fewer load instructions to move the same amount of data — faster.
__global__ void add_kernel(float* A, float* B, float* C, int N) {
int tid = blockIdx.x * blockDim.x + threadIdx.x; // global thread ID
if (tid < N) {
float a = A[tid]; // load (HBM → register)
float b = B[tid]; // load (HBM → register)
float c = a + b; // ALU (register-to-register, ~1 cycle)
C[tid] = c; // store (register → HBM)
}
}
add_kernel<<< 4, 256 >>>(A, B, C, 1024);
What happens per cycle (assuming occupancy 1, the worst case):
cycle: 1 2..99 100 101..199 200 201
---- ------ ---- -------- ---- -----
inst: load wait load wait add store
A (idle) B (idle)
↓
ALU only busy 2 cycles out of 200.
Instructions in this kernel: 4. Actual cycles: ~200. The reason: each HBM load takes ~100 cycles to complete, even though issuing it takes 1 cycle. With occupancy 1, the SIMD has nothing else to do but wait.
If occupancy were 4, the SIMD would switch to other waves during the wait, keeping the ALU busy on every cycle. This is why high occupancy matters.
9. MFMA: cooperative matrix multiply
MFMA (Matrix Fused Multiply-Add) instructions are wave-cooperative: all 64 lanes work together to compute a small matrix multiply (e.g., 16×16).
v_mfma_f32_16x16x16_f16 acc, a_frag, b_frag, c_frag
64 lanes cooperatively compute D = A × B + C
where A is 16×16 fp16, B is 16×16 fp16, D is 16×16 fp32
Each lane holds a small piece of A, B, and accumulates a small piece of D.
The hardware exchanges data between lanes during execution.
Latency: ~8–32 cycles (NOT 1 cycle), but throughput is enormous:
16×16×16 = 4,096 multiply-adds per instruction per wave
Important: MFMA is a wave-level instruction. It cannot be split across waves — one wave executes one MFMA. To compute a larger matrix multiply, multiple waves issue multiple MFMAs (covering different tiles).
Larger vec → fewer load instructions → faster, up to the 16-byte hardware limit.
11. Tile distribution patterns: thread / warp / block raked
The same tile can be distributed across threads in several ways. The choice depends on the algorithm, the data layout, and the matrix instruction (MFMA) shape.
Pattern
Who covers one tile
Wave layout inside tile
thread_raked
1 wave (64 threads)
n/a (single wave)
warp_raked
Multiple waves cooperate
1D stack (waves stripe along one axis)
block_raked
All waves of the workgroup
2D grid (waves arranged in a grid)
warp_raked — 1D wave layout (4 waves stacked along Y)
X axis (XPerTile)
┌─────────────────────────────────┐
│ Wave 0 │ each wave covers full X width
├─────────────────────────────────┤
│ Wave 1 │ 1/4 of Y
├─────────────────────────────────┤
│ Wave 2 │
├─────────────────────────────────┤
│ Wave 3 │
└─────────────────────────────────┘
block_raked — 2D wave layout (4 waves in 2×2 grid)
How to Access Korean-Only Websites from Overseas Using AWS EC2 (Seoul Region VPN)
Some Korean websites (government, financial, public institutions) block access from foreign IP addresses. This guide shows you how to create a quick VPN tunnel through AWS EC2 in Seoul to get a Korean IP address.
What you need: AWS account, AWS CLI installed, Terminal (macOS/Linux)
A D-U-N-S Number (Data Universal Numbering System) is a unique 9-digit business identifier issued by Dun & Bradstreet (D&B). It is used globally to identify and verify businesses for purposes such as:
Enrolling in the Apple Developer Program as an organization
Applying for government contracts and grants
Establishing business credit profiles
Vendor and supplier registration
💡 Apple requires a D-U-N-S Number to verify your organization's legal identity before issuing an Apple Developer team account. Individual accounts do not need one.
2. Prerequisites — Documents to Prepare
Before starting the application, gather the following information and documents:
Item
Description
Business Name
Full legal name exactly as registered
Registration Number
Tax ID or company registration number
Business Address
Full address including postal code and country
Phone Number
International format: +[country code][number]
CEO / Owner Info
Full legal name and title (e.g., Owner, CEO)
Website
Company website URL (if available)
Date Founded
Official business establishment date
Employee Count
Total headcount including yourself
Registration Certificate
English version — PDF format preferred
⚠️ Non-English documents must be translated. Check your country's official tax authority or business registration portal — many offer an official English-language certificate export option directly.
3. Go to the D&B Application Portal
Navigate to the appropriate portal based on your use case:
Use this for general business registration, government contracts, or other purposes.
4. Select Your Request Type
On the Apple Developer D&B portal, you will be asked two questions:
Step 4a
Under "What are you?" → select Developer Program
Step 4b
Under "What do you need?" → select Create New DUNS
5. Search for an Existing D-U-N-S
The portal checks whether your business already has a D-U-N-S number before creating a new one.
Step 5a
Enter your business name and full address in the search fields.
Step 5b
Click "Lookup by Name / Address".
Step 5c — Expected Result
For new businesses: you will see "No Match found" — this is completely normal and expected.
Step 5d
Click "click here to submit a request to create a new D-U-N-S" to open the full application form.
✅ If a match is found, your business already has a D-U-N-S. You can claim or update it instead of creating a new one — contact D&B support directly.
6. Fill Out the Application Form
Complete all fields in the Create D-U-N-S Number form. All fields must exactly match your official registration documents.
Field
What to Enter
Full Legal Business Name
Exact name as on registration documents
Business Registration Number
Your tax ID / company ID number
Company Phone
International format (e.g., +358501234567)
Street Address
Full street address
City
City name
State / Province
State or province (if applicable)
Postal Code
ZIP / postal code
Country
Your country
Business Structure
e.g., Sole Proprietorship, LLC, Corporation
CEO / Owner Name
Full legal name
CEO / Owner Title
e.g., Owner, CEO, Director
Website
Company website URL
Home-Based Business
Yes / No
Number of Employees
Total headcount (including yourself)
Date Founded
Official establishment date (MM/DD/YYYY)
⚠️ Exact match required. The business name, address, and registration number must match your official documents precisely. Even minor differences (abbreviations, punctuation) can cause rejection.
Click "Next" to advance to the document attachment page.
7. Attach Supporting Documents
Upload a document to verify your business registration. This is required — submissions without a document attachment are typically rejected.
Accepted Documents
✅ English Business Registration Certificate (strongly preferred)
✅ Official government-issued business license
✅ Any official document showing your business name, registration number, and address
📄 PDF format is recommended. File size is typically not an issue, but keep it under 5MB to be safe. Make sure the document is clearly legible and all key information is visible.
8. Add Notes & Submit
There is usually a free-text Additional Details / Notes field. Always fill this in — it helps the D&B reviewer understand your submission and can speed up approval.
Example — First-time application
Sample note text
This is a new D-U-N-S number request for [Your Business Name], a sole proprietorship
registered in [Country] since [Year]. Business is engaged in [industry, e.g. software
development]. English Business Registration Certificate is attached.
Example — Resubmission after rejection
Sample note text
Resubmitting after previous rejection (Case #XXXXXXXX) which was closed due to
missing English Business Registration Certificate. The English certificate is now attached.
Business registration number: [Your Number]. Business started: [Date].
After reviewing all information, click Submit.
💾 Save your case number immediately after submission — you will need it to track your application status or to reference in any resubmission.
9. What Happens Next?
After submission, D&B will review your request. Here is the typical timeline:
Immediately
On-screen confirmation + case number displayed. Check your email for a confirmation from D&B (check spam).
1–2 business days
D&B reviews your submitted information and documents.
3–5 business days
D-U-N-S Number issued and emailed to you.
Up to 30 days
In some cases D&B may request additional documentation.
📬 D&B will send your D-U-N-S Number by email. Once received, the number is also searchable via the D&B portal. Apple recommends waiting 24–48 hours after receiving your number before using it for developer enrollment.
10. Troubleshooting: Common Rejection Reasons
Issue
Solution
Missing English document
Obtain an official English translation of your registration certificate and resubmit
Business name mismatch
Ensure the name on the form exactly matches your official documents (character for character)
Address not recognized
Use the exact address format from your registration documents
Duplicate D-U-N-S found
Contact D&B to claim or update the existing record instead of creating a new one
Case closed, no response
Resubmit the form and reference the previous case number in the notes field
Document unreadable
Re-export or rescan the document as a clear, high-resolution PDF
11. Using Your D-U-N-S for Apple Developer Enrollment
Select "Enroll as an Organization" (not Individual).
Step 3
Enter your D-U-N-S Number when prompted. Apple will verify it against D&B's database.
Step 4
Allow 24–48 hours after receiving your D-U-N-S before enrolling — the number needs time to propagate in D&B's system.
✅ The Apple verification process typically takes a few days after enrollment. Apple may call your registered business phone number to verify your identity as the organization's legal representative.
Final Checklist
Prepared English business registration certificate (PDF)
Navigated to the D&B portal (APPLEDEV or general)
Selected correct request type (Developer Program → Create New DUNS)
Searched for existing D-U-N-S — confirmed no match
Filled out all form fields matching official documents exactly