praca_magisterska/pytania/generate_q9_budowa_diagrams.py

378 lines
14 KiB
Python
Raw Permalink Normal View History

2026-03-04 21:45:02 +01:00
#!/usr/bin/env python3
"""
Generate supplementary diagrams for PYTANIE 9 'Budowa procesu' and 'Budowa wątku'.
Replaces ASCII art with monochrome A4-printable PNGs (300 DPI).
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
import os
DPI = 300
BG = 'white'
LN = 'black'
FS = 8
FS_TITLE = 11
FS_SMALL = 6.5
FS_LABEL = 9
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img')
os.makedirs(OUTPUT_DIR, exist_ok=True)
GRAY1 = '#E8E8E8'
GRAY2 = '#D0D0D0'
GRAY3 = '#B8B8B8'
GRAY4 = '#F5F5F5'
GRAY5 = '#C0C0C0'
def draw_box(ax, x, y, w, h, text, fill='white', lw=1.2, fontsize=FS,
fontweight='normal', ha='center', va='center', rounded=True,
edgecolor=LN, linestyle='-'):
if rounded:
rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.05",
lw=lw, edgecolor=edgecolor, facecolor=fill,
linestyle=linestyle)
else:
rect = mpatches.Rectangle((x, y), w, h, lw=lw, edgecolor=edgecolor,
facecolor=fill, linestyle=linestyle)
ax.add_patch(rect)
ax.text(x + w/2, y + h/2, text, ha=ha, va=va, fontsize=fontsize,
fontweight=fontweight, wrap=True)
def draw_arrow(ax, x1, y1, x2, y2, lw=1.2, style='->', color=LN):
ax.annotate("", xy=(x2, y2), xytext=(x1, y1),
arrowprops=dict(arrowstyle=style, color=color, lw=lw))
def save_fig(fig, name):
path = os.path.join(OUTPUT_DIR, name)
fig.savefig(path, dpi=DPI, bbox_inches='tight', facecolor=BG, pad_inches=0.15)
plt.close(fig)
print(f" Saved: {path}")
# ============================================================
# 1. Memory layout with C code annotations
# ============================================================
def gen_memory_c_annotated():
fig, ax = plt.subplots(figsize=(9, 5.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 8)
ax.set_aspect('auto')
ax.axis('off')
ax.set_title('Segmenty pamięci procesu — mapowanie kodu C',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Left side: memory segments stack
seg_x = 1.0
seg_w = 2.8
seg_h = 0.95
gap = 0.08
segments = [
('STACK ↓', GRAY1, 'rośnie w dół'),
('...', 'white', 'wolna przestrzeń'),
('HEAP ↑', GRAY4, 'rośnie w górę'),
('BSS', GRAY2, 'zerowane'),
('DATA', GRAY3, 'zainicjalizowane'),
('TEXT', GRAY5, 'read-only'),
]
seg_positions = {}
top_y = 7.0
for i, (name, color, note) in enumerate(segments):
y = top_y - i * (seg_h + gap)
draw_box(ax, seg_x, y, seg_w, seg_h, name, fill=color,
fontsize=FS_LABEL, fontweight='bold', rounded=False)
ax.text(seg_x + seg_w + 0.15, y + seg_h / 2, note,
fontsize=FS_SMALL, va='center', style='italic', color='#555')
seg_positions[name.split()[0].replace('', '').replace('', '').strip()] = y + seg_h / 2
# Address labels
ax.text(seg_x - 0.15, top_y + seg_h / 2, 'wysoki\nadres',
fontsize=FS_SMALL, va='center', ha='right', style='italic')
ax.text(seg_x - 0.15, seg_positions['TEXT'], 'niski\nadres',
fontsize=FS_SMALL, va='center', ha='right', style='italic')
# Right side: C code with arrows pointing to segments
code_x = 6.5
code_lines = [
('int global_init = 42;', 'DATA', '→ DATA'),
('int global_uninit;', 'BSS', '→ BSS'),
('', None, ''),
('int main() {', 'TEXT', '→ TEXT'),
(' int local = 10;', 'STACK', '→ STACK'),
(' int *p = malloc(100);', 'HEAP', ' p → STACK\n 100B → HEAP'),
(' free(p);', None, ''),
(' return 0;', None, ''),
('}', None, ''),
]
# Code box background
code_top = 7.2
code_line_h = 0.55
total_code_h = len(code_lines) * code_line_h + 0.3
rect = mpatches.FancyBboxPatch((code_x - 0.3, code_top - total_code_h),
5.5, total_code_h,
boxstyle="round,pad=0.1",
lw=1.2, edgecolor=GRAY3, facecolor=GRAY4)
ax.add_patch(rect)
ax.text(code_x + 2.2, code_top + 0.15, 'Kod C — przykład',
fontsize=FS, fontweight='bold', ha='center')
for i, (line, seg, annotation) in enumerate(code_lines):
y = code_top - (i + 1) * code_line_h
ax.text(code_x, y, line, fontsize=7, va='center', family='monospace')
if seg and seg in seg_positions:
# Draw arrow from annotation to segment
ann_x = code_x + 4.0
seg_y = seg_positions[seg]
ax.text(ann_x, y, annotation.split('\n')[0], fontsize=FS_SMALL,
va='center', fontweight='bold', color='#333')
# Connecting line (dashed)
ax.plot([seg_x + seg_w, ann_x - 0.1], [seg_y, y],
linestyle=':', color=GRAY3, lw=0.8)
save_fig(fig, 'q9_memory_c_annotated.png')
# ============================================================
# 2. PCB detailed with concrete values
# ============================================================
def gen_pcb_detailed():
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.set_xlim(0, 10)
ax.set_ylim(0, 7)
ax.set_aspect('auto')
ax.axis('off')
ax.set_title('PCB (Process Control Block) — dowód osobisty procesu',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# PCB outer box
pcb_x, pcb_y, pcb_w, pcb_h = 1.0, 0.8, 8.0, 5.5
rect = mpatches.FancyBboxPatch((pcb_x, pcb_y), pcb_w, pcb_h,
boxstyle="round,pad=0.15",
lw=2, edgecolor=LN, facecolor='white')
ax.add_patch(rect)
ax.text(pcb_x + pcb_w / 2, pcb_y + pcb_h + 0.15, 'PCB procesu PID=1234',
fontsize=FS_LABEL, fontweight='bold', ha='center')
fields = [
('PID', '1234', 'identyfikator procesu'),
('Stan', 'RUNNING', 'aktualny stan wykonania'),
('PC', '0x004015A0', 'następna instrukcja do wykonania'),
('Rejestry CPU', 'EAX=5, EBX=0, ESP=...', 'stan procesora'),
('Tablice stron', '[strona→ramka]', 'mapowanie pamięci wirtualnej'),
('Otwarte pliki', 'fd0, fd1, fd2, ...', 'deskryptory plików'),
('Priorytet', '20 (nice)', 'klasa schedulingu'),
('Czas CPU', '1.34 s', 'accounting / statystyki'),
]
row_h = 0.55
top_y = pcb_y + pcb_h - 0.4
field_w = 2.3
val_w = 3.0
desc_x = pcb_x + field_w + val_w + 0.6
for i, (field, value, desc) in enumerate(fields):
y = top_y - i * (row_h + 0.05)
# Field name box
draw_box(ax, pcb_x + 0.3, y, field_w, row_h, field,
fill=GRAY2, fontsize=FS, fontweight='bold', rounded=False)
# Value box
draw_box(ax, pcb_x + 0.3 + field_w, y, val_w, row_h, value,
fill=GRAY4, fontsize=7.5, rounded=False)
# Description
ax.text(desc_x, y + row_h / 2, desc,
fontsize=FS_SMALL, va='center', style='italic', color='#555')
# Bottom note
ax.text(5.0, 0.35, 'Context switch = zapisz PCB starego procesu → wczytaj PCB nowego',
fontsize=FS, ha='center', style='italic',
bbox=dict(boxstyle='round,pad=0.25', facecolor=GRAY4, edgecolor=GRAY3))
save_fig(fig, 'q9_pcb_detailed.png')
# ============================================================
# 3. Process states with ALL transition labels
# ============================================================
def gen_process_states_labeled():
fig, ax = plt.subplots(figsize=(8, 4.5))
ax.set_xlim(0, 13)
ax.set_ylim(-0.5, 6)
ax.set_aspect('auto')
ax.axis('off')
ax.set_title('Stany procesu — diagram przejść z opisami',
fontsize=FS_TITLE, fontweight='bold', pad=10)
states = {
'NEW': (0.8, 3.0),
'READY': (3.8, 3.0),
'RUNNING': (7.3, 3.0),
'BLOCKED': (7.3, 0.5),
'TERMINATED': (11.0, 3.0),
}
fills = {
'NEW': GRAY4, 'READY': GRAY1, 'RUNNING': GRAY3,
'BLOCKED': GRAY2, 'TERMINATED': GRAY5,
}
bw, bh = 2.0, 1.0
for name, (x, y) in states.items():
draw_box(ax, x, y, bw, bh, name, fill=fills[name], fontsize=FS_LABEL,
fontweight='bold')
# Transition: NEW → READY
sx, sy = states['NEW']
dx, dy = states['READY']
draw_arrow(ax, sx + bw, sy + bh/2, dx, dy + bh/2, lw=1.5)
ax.text((sx + bw + dx) / 2, sy + bh/2 + 0.2, 'admit\n(utworzony)',
fontsize=FS_SMALL, ha='center', va='bottom')
# Transition: READY → RUNNING (dispatch)
sx, sy = states['READY']
dx, dy = states['RUNNING']
draw_arrow(ax, sx + bw, sy + bh * 0.65, dx, dy + bh * 0.65, lw=1.5)
ax.text((sx + bw + dx) / 2, sy + bh * 0.65 + 0.2, 'dispatch\n(scheduler → CPU)',
fontsize=FS_SMALL, ha='center', va='bottom')
# Transition: RUNNING → READY (preemption)
draw_arrow(ax, dx, dy + bh * 0.35, sx + bw, sy + bh * 0.35, lw=1.5)
ax.text((sx + bw + dx) / 2, sy + bh * 0.35 - 0.15, 'preempt\n(kwant czasu)',
fontsize=FS_SMALL, ha='center', va='top')
# Transition: RUNNING → TERMINATED
sx, sy = states['RUNNING']
dx, dy = states['TERMINATED']
draw_arrow(ax, sx + bw, sy + bh/2, dx, dy + bh/2, lw=1.5)
ax.text((sx + bw + dx) / 2, sy + bh/2 + 0.2, 'exit()',
fontsize=FS_SMALL, ha='center', va='bottom')
# Transition: RUNNING → BLOCKED
sx, sy = states['RUNNING']
dx, dy = states['BLOCKED']
draw_arrow(ax, sx + bw/2, sy, dx + bw/2, dy + bh, lw=1.5)
ax.text(sx + bw + 0.2, (sy + dy + bh) / 2, 'I/O wait\n(np. read z dysku)',
fontsize=FS_SMALL, ha='left', va='center')
# Transition: BLOCKED → READY
bx, by = states['BLOCKED']
rx, ry = states['READY']
ax.annotate("", xy=(rx + bw/2, ry), xytext=(bx, by + bh/2),
arrowprops=dict(arrowstyle='->', lw=1.5, color=LN,
connectionstyle='arc3,rad=0.35'))
ax.text(4.0, 1.0, 'I/O done\n(powrót do kolejki)',
fontsize=FS_SMALL, ha='center')
# Legend at bottom
legend_items = [
'NEW → READY: proces utworzony, gotowy',
'READY → RUNNING: scheduler przydziela CPU',
'RUNNING → READY: upłynął kwant czasu (preemption)',
'RUNNING → BLOCKED: czeka na I/O',
'BLOCKED → READY: I/O zakończone',
'RUNNING → TERMINATED: proces kończy się',
]
for i, item in enumerate(legend_items):
col = i // 3
row = i % 3
ax.text(0.5 + col * 6.5, -0.1 - row * 0.35, f'{item}',
fontsize=FS_SMALL, va='center')
save_fig(fig, 'q9_process_states_labeled.png')
# ============================================================
# 4. Thread shared vs private — annotated diagram
# ============================================================
def gen_thread_shared_private():
fig, ax = plt.subplots(figsize=(9, 5.5))
ax.set_xlim(0, 12)
ax.set_ylim(0, 8)
ax.set_aspect('auto')
ax.axis('off')
ax.set_title('Wątki wewnątrz procesu — współdzielone vs prywatne',
fontsize=FS_TITLE, fontweight='bold', pad=10)
# Outer process box
proc_rect = mpatches.FancyBboxPatch((0.5, 0.3), 11.0, 7.0,
boxstyle="round,pad=0.15",
lw=2.5, edgecolor=LN, facecolor='white')
ax.add_patch(proc_rect)
ax.text(6.0, 7.55, 'PROCES (PID = 1234)', fontsize=FS_LABEL,
fontweight='bold', ha='center')
# Shared region (top)
shared_rect = mpatches.Rectangle((1.0, 4.5), 10.0, 2.5,
lw=1.5, edgecolor=LN, facecolor=GRAY1)
ax.add_patch(shared_rect)
ax.text(6.0, 6.75, 'WSPÓŁDZIELONE (wszystkie wątki widzą to samo)',
fontsize=FS, fontweight='bold', ha='center')
shared_items = [
('TEXT', 'kod programu'),
('DATA', 'zm. globalne\nzainicjalizowane'),
('BSS', 'zm. globalne\nniezainicjalizowane'),
('HEAP', 'malloc/new\n(dynamiczna)'),
('Pliki', 'deskryptory\nfd[0..n]'),
('PID', 'identyfikator\nprocesu'),
]
for i, (name, desc) in enumerate(shared_items):
x = 1.4 + i * 1.6
draw_box(ax, x, 4.7, 1.3, 0.7, name, fill=GRAY3,
fontsize=FS, fontweight='bold', rounded=False)
ax.text(x + 0.65, 5.6, desc, fontsize=5.5, ha='center', va='center')
# Private region (bottom) — 3 threads
private_rect = mpatches.Rectangle((1.0, 0.6), 10.0, 3.5,
lw=1.5, edgecolor=LN, facecolor='white',
linestyle='--')
ax.add_patch(private_rect)
ax.text(6.0, 3.85, 'PRYWATNE (każdy wątek ma WŁASNE)',
fontsize=FS, fontweight='bold', ha='center')
thread_colors = [GRAY4, '#E0E0E0', GRAY4]
for t in range(3):
tx = 1.5 + t * 3.3
tw = 2.8
thread_rect = mpatches.FancyBboxPatch((tx, 0.8), tw, 2.7,
boxstyle="round,pad=0.1",
lw=1.5, edgecolor=LN,
facecolor=thread_colors[t])
ax.add_patch(thread_rect)
tid = t + 1
ax.text(tx + tw/2, 3.25, f'Wątek {tid} (TID={40+tid})',
fontsize=FS, fontweight='bold', ha='center')
private_items = [
(f'Stos_{tid}', 'zmienne lokalne'),
(f'Rejestry_{tid}', 'EAX, EBX, ESP...'),
(f'PC_{tid}', 'pozycja w kodzie'),
]
for j, (name, desc) in enumerate(private_items):
y = 2.65 - j * 0.6
draw_box(ax, tx + 0.15, y, tw - 0.3, 0.45, f'{name}',
fill='white', fontsize=7, fontweight='bold', rounded=False)
ax.text(tx + tw/2, y - 0.1, desc, fontsize=5.5, ha='center',
va='top', color='#555')
save_fig(fig, 'q9_thread_shared_private.png')
# ============================================================
# MAIN
# ============================================================
if __name__ == '__main__':
print("Generating supplementary PYTANIE 9 'Budowa' diagrams...")
gen_memory_c_annotated()
gen_pcb_detailed()
gen_process_states_labeled()
gen_thread_shared_private()
print("\nAll 4 supplementary diagrams generated!")