* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: workerthread.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
#include "blaze_globals.h"
#include "cpu_interface.h"
#include "vtracer_async_queue.h"
static inline void * system_worker_thread (void * arg
);
static volatile uint64_t GlobalTimeUsecs
;
// each workerthread maintains a local copy time variable, which is
// used for comparison in doEventQueueCallbacks()
volatile uint64_t simTime
;
// approximate tick count per cpu/strand. only for "mips" ui-cmd,
// this is currently Broken ~!~
static volatile int64_t GlobalTicks
;
static WorkerThread
* wrkthds
; // worker thread array
static volatile int numThds
; // total number of workerthreads
pthread_t tid
; // the real worker thread
int worker_id
; // 0..numthds-1
int num_cpus
; // # of vcpu's assigned to this workerthread
Vcpu
*cpus
[MAX_MP
]; // pointers to vcpu's assigned to this thread,
// index = [0 ... num_cpus - 1]
EventQue
* eq
; // per worker thread event queue
static pthread_key_t key
; // to bind the eq to workerthread's private data
int64_t done_x_1024
[MAX_MP
];
called_from_stept
= false;
Nusecs
= Ninstrs
= Ncycles
= 0;
sema_init (&KICK
,0, USYNC_THREAD
, NULL
);
assert (pthread_create (&tid
,NULL
, &system_worker_thread
, (void*)this) == 0);
/////assert (pthread_setspecific(key,(void *) this) == 0);
simTime
= GlobalTimeUsecs
;
sema_t KICK
; // <--- KICK semaphores
static int64_t Nusecs
; /* stept microseconds */
static int64_t Ninstrs
; /* stepi instruction count */
static int64_t Ncycles
; /* for exec-driven mode */
static volatile int BarrierCount
;
static volatile int BarrierLock
;
static volatile int BarrierTemp
;
static volatile uint64_t step_remainder
; /* see note in .cc for explanation */
static volatile uint64_t stick_incr
;
// to allow for stick frequencies that are not a multiple of 10^6
static volatile uint64_t stick_remainder
;
void stept(uint64_t usecs
);
void stepc(int64_t ncycles
);
static void kill_worker_threads ();
void doEventqueCallbacks (){
&& eq
->top_time() <= simTime
) {
(*(EventFunc_T
*)event
.pq_cbfunc
) (event
.pq_cbarg1
, event
.pq_cbarg2
);
if (cpus
[0] == first_cpu
) {
while (trace_async_queue
->getsize()) {
VCPU_AsyncData async_rec
;
trace_async_queue
->dequeue(&async_rec
);
first_cpu
->sys_intf
.vtrace
->async(&async_rec
);
} // if this is the first cpu in the system
// write sync records to all cpus. Use GlobalTimeUsecs as a possible seq #
vtracer_syncinfo syncinfo
;
syncinfo
.synctype
= vtracer_syncinfo::synctype_LOCAL
;
syncinfo
.syncid
= GlobalTimeUsecs
;
for (i
=0; i
<num_cpus
; i
++) {
syncinfo
.cpuid
= cpus
[i
]->id();
cpus
[i
]->sys_intf
.vtrace
->sync(&syncinfo
);
// external interface exported by workerthreads
assert (pthread_setspecific(key
,(void *) this) == 0);
sema_wait (&KICK
); // --------------------------------- STANDBY !!!
static void kick_stepi(uint64_t n
){
// initialize the stick related variabled
stick_incr
= the_arch
.stick_freq
/1000000ull;
create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(),\
SYSTEM_get_numthreads());
Ninstrs
= n
; Nusecs
= 0; Ncycles
= 0;
for (int i
= 0; i
< numThds
; i
++)
sema_post (&wrkthds
[i
].KICK
);
static void kick_stept(uint64_t usecs
){
// initialize the stick related variabled
stick_incr
= the_arch
.stick_freq
/1000000ull;
create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(), \
SYSTEM_get_numthreads());
Nusecs
= usecs
; Ninstrs
= 0; Ncycles
= 0;
for (int i
= 0; i
< numThds
; i
++)
sema_post (&wrkthds
[i
].KICK
);
static void kick_stepc(int64_t ncycles
) {
stick_incr
= the_arch
.stick_freq
/1000000ull;
create_worker_threads(SYSTEM_get_ncpu(), SYSTEM_get_ncpu(), 1);
Ncycles
= ncycles
; Nusecs
= Ninstrs
= 0;
sema_post(&wrkthds
[0].KICK
);
for (int j
=0; j
< num_cpus
; j
++)
if (j
>0) ui
->verbose (",");
ui
->verbose ("%d", cpus
[j
]->id());
static void registerEvent (uint64_t stime
,
EventFunc_T
* callbackfunc
, void* arg1
, void* arg2
,
UnloadFunc_T
* unloadfunc
,
const char * debugstring
)
WorkerThread
* wt
= (WorkerThread
*) pthread_getspecific (key
);
EventQue
* myeq
= wt
? wt
->eq
: 0;
create_worker_threads(SYSTEM_get_ncpu(),
SYSTEM_get_cpus_per_thread(),
SYSTEM_get_numthreads());
myeq
->insert_callback ( stime
, (void*)callbackfunc
, arg1
, arg2
,
(void*)unloadfunc
, debugstring
,
(wt
? wt
->worker_id
: -1));/*more debug*/
static void doEventqueUnloads ()
for (int i
= 0; i
< numThds
; i
++)
static void doEventquePrint ()
for (int i
= 0; i
< numThds
; i
++)
static void create_worker_threads (int NumCpus
, int cpusPerThread
, int numThreads
);
// store any needed parameter in the form of NAME VALUE pair in fp
static void dump(FILE * fp
);
// restore parameters stored in the form of NAME VALUE pair from fp
static int restore(char * line
);
static uint64_t get_time(){
WorkerThread
* wt
= (WorkerThread
*) pthread_getspecific(key
);
return (wt
? wt
->simTime
: GlobalTimeUsecs
);
static int64_t get_ticks(){ return GlobalTicks
;}
static volatile int64_t u_instrs
; // for "mips" ui command
static volatile int64_t k_instrs
;
static volatile int64_t u_intervals
; // ditto
static volatile int64_t k_intervals
;
static inline void * system_worker_thread (void * arg
){
WorkerThread
* sp
= (WorkerThread
*) arg
;