# ClientApp: high-level design

[Repository overview](../README.md) | [Low-level design](ClientApp_LLD.md) | [Complexity](ClientApp_COMPLEXITY.md)

## Purpose

ClientApp is the console entry point for demonstrating and checking HeapManager. It creates one custom heap, runs single-threaded checks, runs a multithreaded workload, prints reports, and destroys the heap.

The original workload stays in [ClientApp.cpp](ClientApp.cpp). [Portfolio.cpp](Portfolio.cpp) and [Portfolio.h](Portfolio.h) add command dispatch support, regression tests, named scenarios, and snapshot export without replacing that workload.

| Command | Responsibility |
| --- | --- |
| No arguments | Original single-thread and eight-thread tests, with final counter assertions. |
| `--test` | Original workload, allocator/list/logger regressions, and all named scenarios. |
| `--scenario NAME` | Run one named native demonstration, or `all`. |
| `--export FILE [NAME]` | Run scenarios and publish their validated snapshots as JSON. |
| `--help` | Print usage; malformed arguments return exit code 2. |

## Original design used

The client-design guidance comes from the following files under `C:\Temp\EE Intern - Himanshu`:

- `Study Guides/Heap Manager Designs/1/HLDSteps.md`, especially the debug-layer/client-harness stage.
- `Study Guides/Heap Manager Designs/1/LLDSteps.md`, especially the small `client/main.c` harness sketch.
- `VS_EE_Intern_Solution/Assignment_7/Assignment_7.cpp`, the full client originally brought into this project.

There is no separate Assignment 7 HLD/LLD file in the matching project folder. The design notes live under the study guides. This document adapts their testing intent to `ClientApp.cpp`; it does not claim that the original sketch or each intermediate allocator stage is shipped here as another program.

## How the client checks the original design ideas

The original notes build from a minimal allocator toward splitting, coalescing, growth, synchronization, and diagnostics. The client is meant to exercise the combined library from outside rather than manipulate its internal list links.

The following table describes the retained original phase. The separate regression suite deliberately damages and restores selected metadata on its own test heaps to check rejection; it is not normal application usage.

| Original design idea | Current client activity | What this establishes |
| --- | --- | --- |
| Allocate usable memory | Request several sizes, fill bytes, and read them back. | Returned payloads work for those cases; it is not a general alignment or overflow test. |
| Reuse freed space | Repeated 128-byte allocations and random live slots. | Exercises reuse; it does not assert exact split addresses or every coalescing branch. |
| Resize while preserving data | Grow 64 bytes to 512 and compare the original 64 bytes. | Checks the preserved prefix for that case, not every realloc path. |
| Grow committed memory on demand | Let the shared workload exceed the initial committed chunk as needed. | Exercises integration with growth; no assertion requires an exact commit count or forces OS failure. |
| Protect shared bookkeeping | Eight threads use one heap with privately owned payloads. | Checks the observed workload for allocation failures and pattern damage; does not prove every schedule is safe. |
| Make problems visible | Validate and print reports after both phases. | Validation failures and final live-byte/block/allocation/free counters affect the result; arbitrary logger messages are not automatically assertions. |

```mermaid
flowchart LR
	D["Original allocator design idea"] --> T["Exercise through public my_* calls"]
	T --> P["Check payload results and heap layout"]
	P --> R["Report failures and heap counters"]
```

This preserves the original incremental-design story without turning intended properties into unimplemented test guarantees.

## Main parts

| Part | Responsibility |
| --- | --- |
| `main` | Owns the heap and orders the two test phases. |
| Single-threaded tests | Check allocation, writable data, zero-fill, realloc preservation, and repeated reuse. |
| Worker manager | Creates eight Windows threads, waits for them, gathers failures, and closes handles. |
| Worker function | Maintains its own live-pointer slots and performs random allocate or verify/free operations. |
| Pattern helpers | Write predictable bytes and detect a mismatch later. |
| Heap validation/report calls | Check parts of the physical heap layout and display counters. |
| Portfolio scenario runner | Assert split/merge, cache reuse/reclamation, growth, and concurrent ownership on dedicated heaps. |
| Snapshot/export helpers | Copy consistent native state and serialize offsets/counters after releasing the heap lock. |
| Regression suites | Exercise overflow, alignment, pointer/state rejection, snapshot sizing, list APIs, and logger lifecycle. |

The flow below covers the original phase and optional `--test` extensions; scenario/export commands dispatch before creating the original workload's heap.

```mermaid
flowchart TD
	A["Start ClientApp"] --> B["Create one 16 MiB reserved heap"]
	B --> C{"Heap created?"}
	C -->|"No"| X["Print fatal error; exit 1"]
	C -->|"Yes"| D["Run single-threaded tests"]
	D --> E["Validate heap and print report"]
	E --> F["Run eight worker threads"]
	F --> G["Join workers and collect failures"]
	G --> H["Validate heap and print report"]
	H --> I["Destroy heap"]
	I --> M{"Running --test?"}
	M -->|"Yes"| Y["Run regressions and all portfolio scenarios"]
	M -->|"No"| J{"Failure count is zero?"}
	Y --> J
	J -->|"Yes"| K["ALL TESTS PASSED; exit 0"]
	J -->|"No"| L["Print failure count; exit 1"]
```

## Relationship to the other projects

ClientApp calls the exported `my_*` functions in `HeapManager.dll`. The heap uses intrusive node links and emits messages through its statically linked Debugger code.

The client project references HeapManager, Debugger, and Intrusive_LinkedList. The original workload calls the heap API and Windows/CRT functions; portfolio regressions also directly exercise list operations and the executable's logger copy. The DLL's logger copy remains separate, with automatic synchronization and its own optional sink.

This distinction matters: a passing default run covers the original workload, while `--test` covers the additional library regressions. Neither is a proof of every possible interleaving or misuse case.

## Why use byte patterns?

Simply getting a non-null pointer is not enough. A faulty allocator might return overlapping blocks or damage a payload while updating metadata.

The client fills data with a repeatable pattern, then compares it with the expected bytes. In the worker workload, a block can remain alive across many other heap operations before it is checked and freed. This can expose corruption that an immediate allocation/free pair would miss.

## Threading design

All workers share one heap, but each worker owns its own arrays of pointers, sizes, and pattern seeds. Workers do not hand payloads to each other.

```mermaid
flowchart LR
	M["Main thread"] --> A["Worker 0: private slots"]
	M --> B["Worker 1: private slots"]
	M --> C["Workers 2 through 7: private slots"]
	A --> H["Shared HeapManager heap"]
	B --> H
	C --> H
	H --> L["Heap metadata lock"]
```

The test uses `CreateThread` directly. It does not use a thread pool, IOCP, or the Windows thread-pool API. The eight workers are the workload itself, not a pool that accepts separate jobs.

## Expected result and limits

A successful run prints `RESULT: ALL TESTS PASSED` and returns zero. A healthy final report shows zero live and leaked blocks.

The portfolio verification passed on x64 and Win32 in Debug and Release. Named scenarios assert meaningful outcomes rather than only printing snapshots. Invalid-input regression cases can intentionally emit error logs; explicit checks and exit codes determine pass/fail. Tests do not prove every OS failure, arbitrary metadata attack, or schedule safe, and no allocator benchmark is claimed.

## Real snapshots, not a JavaScript allocator

```mermaid
flowchart LR
	S["Named native scenario"] --> H["my_heap_snapshot: validate and copy under lock"]
	H --> J["Version 1 JSON writer outside the lock"]
	J --> F["Publish file only after success"]
	F --> V["Static index.html: replay and inspect"]
```

Each snapshot contains block offsets/states, sizes, counts, and bucket occupancy. It never contains payload contents or process addresses. The bundled example comes from a real x64 Release export. The page runs independently of Windows once data has been captured, and locally selected files are never uploaded. Imported data is checked structurally, not authenticated.

The website is a technical write-up first: problem and architecture, allocation lifecycle, memory layout, LFH policy, design tradeoffs, debugging/validation, tests, then the supporting dark dashboard. Limitations, future work, and implementation lessons follow it. The benchmark section is a planned experiment, explicitly marked unmeasured rather than presenting correctness tests as performance evidence.

The dashboard adds scenario cards, a keyboard-accessible timeline, playback pace, state/changed-range filters, and a What changed panel. Comparisons use the immediately preceding frame in the selected scenario, not the last frame the reader happened to view. They describe visible ranges and counter differences; they cannot establish allocation identity or reconstruct every intervening operation.

The LFH formula calculator is a separate teaching aid using the current cap/keep constants. Its selected demand changes only its own displayed result, never the trace or native allocator settings. Short snapshot fades respect reduced motion and do not synthesize intermediate memory layouts.

The concurrent visualization scenario uses four workers paused at an event barrier with 16 blocks each; the original stress test still uses eight workers and 20,000 operations each. The scenario demonstrates an observable ownership state without pretending that browser playback controls native execution.

See the [LLD](ClientApp_LLD.md) for exact inputs and failure handling, and [COMPLEXITY](ClientApp_COMPLEXITY.md) for the workload's time and storage bounds.
