Attributes¶
A session carries named numeric attributes, initially 0. Names assigned by
typed declarations, set or choose in session code
are attributes; a set in a stage’s iteration body instead assigns a stage
register. The built-in attributes below need no assignment.
A name may not be both an attribute and a let constant, and neither may take
a context variable's name. Nor may a declaration (a def, an
observe, a stage, a pool, a device, an engine, a queue, a
gauge or a claim) take an attribute's name, built in or set: stage
think beside the built-in think would make the one word mean two things.
A program may still set a built-in attribute (set more = …).
Sizes, values and costs¶
Use Size name = expression; to declare request quantities, and
Cost name = cost(resource, expression); to declare a scalar resource cost.
Existing set assignments still infer their types. Assignments in the workload produce Size:
request quantities and client state. The server may read them but cannot
assign them. Server assignments produce ordinary Value bookkeeping or a
resource-specific Cost. Calculate remaining work or a bounded response in
a separate server attribute; keep the client's original request unchanged.
cost(resource, expression) interprets an ordinary quantity as that
resource's cost. run requires a stage cost; hold, grow and load
require pool costs. For example:
workload {
arrive batch(1);
turn { Size items = 3; }
session { turn; }
}
server {
Cost processing = { mem: items, svc: 2 * items };
hold mem (processing.mem) { run svc (processing.svc); }
}
Here svc and mem are declared resources. The same three items cost six
seconds at a FIFO svc with this conversion. Changing the coefficient
changes the deployment model without changing the workload.
A composite Cost declares one independent amount per named resource.
processing.mem is a pool cost and processing.svc is a stage cost: they
cannot be substituted for one another. The declaration evaluates fields
once, in written order; using a field reads its stored value. Cost duration
= processing.svc; copies a scalar cost without repeating its calculation.
Resource fields name families without member indices; the consuming
hold or run chooses a member normally.
These declarations use the existing session attributes, not block-local storage. A composite name must differ from scalar attributes, constants and resources. Repeating a composite declaration must retain its fields and their order. Composite records are accessed through their scalar fields; whole-record arithmetic and assignment are not supported.
Size is an ownership type, not a physical unit: tokens, bytes, client
continuation flags and thinking intervals are all ordinary quantities.
The type checker cannot infer whether an arbitrary numeric formula was
intended as service time. It requires the server to state the resource
interpretation explicitly. cached and computed are scheduler-owned
Values; the other built-ins below are Sizes.
Costs preserve their type through aliases, scalar multiplication or
division, negation, and abs, floor, ceil. Addition, subtraction,
min, max, comparisons and conditional branches require matching cost
types. A cost cannot be mixed with a bare number or converted to another
resource's cost. Costs must be assigned on every path before use. A cost
attribute used by a hold's cache must already be assigned before entering
the hold, since release, rejection and preemption can end it early.
Workload init and turn cannot construct or read costs. A client's
session can use its own resources, such as a tool stage or a
conversation-wide reservation, but cannot create or read costs of stages
run or pools acquired, grown or loaded by the server. Scheduling declarations, gauges and
claims use ordinary quantities; observe can record a cost's numeric value.
See cost for resource families and evaluation timing.
Built-in attributes¶
| Name | Set by | Meaning |
|---|---|---|
serial |
arrival | arrival order, counted from 0 |
turn_no |
turn; |
turns taken so far: 0 before the first turn;, 1 after it |
cached |
admission | units of the session's own cached prefix consumed at its last admission (reuse); 0 after the admission of a hold without cache, which consumes none |
computed |
preemption | the position the hold had computed when it was preempted; 0 on a first execution and after a hold completes |
With a trace, turn; also sets:
| Name | Meaning |
|---|---|
new |
new tokens this turn brings |
out |
output tokens of the turn |
think |
the think time the trace records for the turn |
more |
1 while another turn remains, 0 after the last |
forced |
1 if the trace forces the turn to miss the prefix cache (an optional sixth column, else 0) |
cached and computed are set by the scheduler, so they cannot be
hidden.
A program that resumes after a preemption reads computed; one that
recomputes from the prompt alone does not read it.
Examples¶
A complete program:
fn main() {
stage svc : delay;
workload {
arrive batch(2);
}
server {
run svc (cost(svc, 1));
observe request_id = serial;
observe current_turn = turn_no;
}
}
Save as model.sq, then run: