mirror of
https://github.com/kuhyx/praca_magisterska.git
synced 2026-07-04 13:43:05 +02:00
378 lines
14 KiB
Python
378 lines
14 KiB
Python
|
|
#!/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!")
|