Key concepts: Threadpools

Since TSLoad is designed to simulate multi-user environments, it has concept of a worker, elementary process that handles user requests. For real application meaning of "worker" may vary - it may be OS-level process or thread or userspace thread. Latter is usually referred as asynchronicity, because such frameworks usually spawn one userspace thread per user request, so all each request handled asynchronously. Examples of userspace threads are Erlang processes, Scala actors or Python Twisted deferreds (they actually use Python generators). Currently only worker supported by TSLoad is OS-level thread, so we will refer worker pool as threadpool in this documentation (and code too).

Threadpool consists of control thread and set of worker threads. Threadpool is synchronous: timeline of threadpool is separated into steps, and at beginning of each step, it generates requests that have to be executed during this step. Step duration interval is constant and called quantum, while second primary parameter of threadpool is num_threads that represents number of workers in this pool. Each step is parametrised by number of requests per each workload class that should be run during this step.

NOTE: Threadpools are deprecated as of TSLoad 0.2. They will be replaced with more flexible and modular loaders and channels.

Threadpool dispatchers

At beginning of each step requests are represent a queue, so they have to be dispatched to worker threads. To do so, worker and control threads are calling dispatcher. There are three main implementations of it in TSLoad 0.2:

There also one parameter common for all dispatchers - discard. If it is set to true, then dispatcher will discard all requests that remain from previous step.

Threadpool scheduling

TSLoad also capable of setting OS scheduler options for worker threads. This functionality provided by libtscommon "schedutil" module and works on all platforms (while scheduler options may vary on different platforms). Workers may be bound to the specific CPU object, which could be chip, NUMA node, core or hardware thread (or strand in terminology of TSLoad) or cache object. You may also create set of them. Actual binding through "set thread affinity call" (for example, sched_setaffinity() in Linux) and selected set of objects is converted to CPU mask. Second scheduling capability is setting parameters (that are usually policy and priority) individually for each thread.

NOTE: Solaris doesn't have such "affinity call" - instead of that it provides processor_bind() that could bind thread only to single hardware thread. If you specify more than one thread in objects parameter, TSLoad will attempt to create a processor set which uses processors exclusively.

To list available scheduler options and CPU objects, use tshostinfo command.

Configuration examples

Here are simplest thread pool that constists of 2 threads and with one-second quantum (all times in TSLoad have nanosecond-resolution):

"test_tp" : {
   "num_threads": 2,
   "quantum": 1000000000,
   "disp": {
        "type": "random"
   }
}

Here an example of "sched" parameter used to set scheduler options for Linux:

    "sched": [
        { "wid": 0,
          "objects": ["strand:0:0:0"],
          "policy": "idle",
          "params": { "nice" : 0 } },
        { "wid": 1,
          "objects": ["strand:0:0:0"] },
        { "wid": 2,
          "objects": ["strand:0:0:0"],
          "policy": "normal",
          "params": { "nice" : 5 } },
        { "wid": 3,
          "objects": ["strand:0:0:0"] }                 
    ]

All of four workers are bound to same hardware thread, policy of first worker (which is identified by "wid" and enumerated from zero) is set to idle, and priority of third worker is adjusted.