Loader agent protocol - myaut/tsload GitHub Wiki
Describes loader agent API in com.vperflab.tsserver Updated to version 0.2
UML sequence diagram for Loader agent is shown here: LoaderAgentSequence.png
NOTE: various annotation helpers are cleaned to reduce this article
Comments on Server-Agent interaction
Running workload constists of X steps:
hello()
Loader agent is started on target system. It opens JSON-TS connection to server and then invokes hello():
def hello(client: TSClient[TSLoadClient], info: TSHostInfo) : TSHelloResponse
It provides various information about host (hostname, number of processors, amount of memory and so on) in info
parameter. If server successfully registers loader agent, it returns id of agent from database in TSHelloResponse. Agent id currently is not used in further communication.
getWorkloadTypes()
Server asks for loader configuration, list of modules that shipped with agent in particular.
def getWorkloadTypes : TSWorkloadTypeList
Agent returns Map(wltypeName -> TSWorkloadType):
class TSWorkloadType extends TSObject {
var module: String = _
var path: String = _
@TSObjContainer(elementClass = classOf[TSWorkloadParamInfo])
var params: Map[String, TSWorkloadParamInfo] = _
}
class TSWorkloadTypeList extends TSObject {
@TSObjContainer(elementClass = classOf[TSWorkloadType])
var wltypes: Map[String, TSWorkloadType] = _
}
For each parameter agent defines:
name
(as key in TSSingleModuleInfo.params map)description
type
(string, integer, etc.). Depending on type, one of TSWorkloadParamInfo derivatives will be instantiated by JSON-TS deserializator:- TSWLParamBooleanInfo
- TSWLParamIntegerInfo
- TSWLParamFloatInfo
- TSWLParamSizeInfo
- TSWLParamStringInfo
- TSWLParamStringSetInfo
default
- default value for paramrange
- minimum and maximum for numbers, maximum length for stringmeta-type
- additional info that determines what type of data this param representing (i.e. integer may represent time) - not implented yet
NOTE: default
and range
params are optional, so it can be nil
configureWorkload()
User desides to start expreriment. Therefore, server sends configure_workload command to client:
def configureWorkload(workloadName: String, workloadParams: TSWorkload)
Where workloadParams:
class TSWorkload extends TSObject {
var module: String = _
var threadpool: String = _
var params: Map[String, AnyRef] = _
}
module
- name of module which will configure/run workloadthreadpool
- name of threadpool that will execute workload. For now only[DEFAULT]
is validparams
- Map(paramName -> paramValue). **NOTE: ** Due to bug (?) in JSON-TS, parameter values should be Java-typed (not Scala-typed)
After that, loader agent spawns configuration thread and prepares to configure workload.
workloadStatus()
During configuration of workload, agent notifies server on configuration status.
def workloadStatus(client: TSClient[TSLoadClient], status: TSWorkloadStatus)
Where status is:
object TSWorkloadStatusCode {
val CONFIGURING = 1
val SUCCESS = 2
val FAIL = 3
val FINISHED = 4
val RUNNING = 5
}
class TSWorkloadStatus extends TSObject {
var workload: String = _
var status: Long = _
var progress: Long = _
var message: String = _
}
workload
- name of reported workloadprogress
- number charasteristic of progressstatus
- status code for workloadCONFIGURING
- workload is configuringSUCCESS
- workload configuration is successfully finished. progress = 100FAIL
- failure encountered during workload configuration or execution. progress = -1FINISHED
- workload execution is finishedRUNNING
- workload execution is currently running. progress = #id of current step
message
- status message
NOTE: since agent 0.2, done
renamed to progress
startWorkload()
When server receives SUCCESS workload status message, it may start workload. Workload are started not immediately start_workload command received because when multiple systems are involved in experiment, network latency may cause mismatch between start times of workload. Server transfers startTime in nanoseconds from UNIX epoch:
def startWorkload(workloadName: String, startTime: Long)
provideStep()
Server feeds agent with step data.
def provideStep(workloadName: String, stepId: Long, numRequests: Long) : TSProvideStepResult
If step queue on agent is full, server will return result != 0:
class TSProvideStepResult extends TSObject {
var result: Long = _
}
requestsReport()
When agent workers are finished execution of step, they report agent statistics per each request to server:
def requestsReport(client: TSClient[TSLoadClient], report: TSRequestReport)
Where report is:
object TSRequestFlag {
val STARTED = 0x01
val SUCCESS = 0x02
val ONTIME = 0x04
val FINISHED = 0x08
}
class TSRequest extends TSObject {
var workload_name: String = _
var step: Long = _
var request: Long = _
var thread: Long = _
var start: Long = _
var end: Long = _
var flags: Long = _
}
class TSRequestReport extends TSObject {
var requests: List[TSRequest] = _
}
workload_name
- name of workloadstep
- id of steprequest
- id of request in step (0 .. numRequests)thread
- id of thread executed requeststart
,end
- start and finish time of request execution (in ns, starting from UNIX epoch)flags
STARTED
- request execution is startedSUCCESS
- request successfully executedONTIME
- request finished execution before quantum was exhaustedFINISHED
- requests execution is finished
workloadStatus()
When no steps are left on steps queue for workload, workload is destroyed and workload_status message is sent to server.
Threadpool API
getThreadPools()
Returns available thread pools and dispatchers
def getThreadPools : TSThreadPoolList
class TSThreadPool extends TSObject {
var num_threads: Long = _
var quantum: Long = _
var wl_count: Long = _
var disp_name: String = _
@TSObjContainer(elementClass = classOf[String])
var wl_list: List[String] = _
}
class TSThreadPoolList extends TSObject {
@TSObjContainer(elementClass = classOf[String])
var dispatchers: List[String] = _
@TSObjContainer(elementClass = classOf[TSThreadPool])
var threadpools: Map[String, TSThreadPool] = _
}
num_threads
- number of threads configured in threadpoolquantum
- thread pool quantum in nanosecondswl_count
- number of workloads attached to threadpooldisp_name
- name of dispatcher used by threadpoolwl_list
- list of workload names
createThreadPool()
def createThreadPool(threadpoolName: String, numThreads: Long, quantum: Long, dispName: String)
destroyThreadPool()
def destroyThreadPool(threadpoolName: String)
Examples
Configuring workload:
import java.lang.{Boolean => JBoolean, Integer => JInteger, Double => JDouble}
def configureTestWorkload(client: TSClient[TSLoadClient]) {
var workload = new TSWorkload()
workload.module = "dummy"
workload.threadpool = "[DEFAULT]"
workload.params = Map("filesize" -> (16777216 : JInteger),
"blocksize" -> (4096 : JInteger),
"path" -> "/tmp/testfile",
"test" -> "read",
"sparse" -> (false : JBoolean))
var workloads = new TSWorkloadList(Map("test" -> workload))
client.getInterface.configureWorkloads(workloads)
}
Start workload:
def startTestWorkload(client: TSClient[TSLoadClient]) {
/*Add five seconds and convert ms to ns*/
var startTime: Long = (System.currentTimeMillis() + 5000) * 1000 * 1000
client.getInterface.startWorkloads(new TSWorkloadStartList(Map("test" -> startTime)));
/*Create 12 steps, 10 requests per step*/
var testSteps = new TSWorkloadSteps()
testSteps.workloadName = "test"
testSteps.steps = (1 to 12).map(i => new TSWorkloadStep(i, 10)).toList
client.getInterface.provideSteps(testSteps)
}