Files
unison/src/simulator/simulator.cc
2006-09-02 12:09:59 +02:00

396 lines
7.9 KiB
C++

/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 2005,2006 INRIA
* All rights reserved.
*
* This 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;
*
* This 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "simulator.h"
#include "scheduler.h"
#include "event.h"
#include "event.tcc"
#include "ns3/system-semaphore.h"
#include <math.h>
#include <cassert>
#include <fstream>
#include <list>
#include <vector>
#include <iostream>
#define noTRACE_SIMU 1
#ifdef TRACE_SIMU
#include <iostream>
# define TRACE(x) \
std::cout << "SIMU TRACE " << Simulator::now_s () << " " << x << std::endl;
# define TRACE_S(x) \
std::cout << "SIMU TRACE " << x << std::endl;
#else /* TRACE_SIMU */
# define TRACE(format,...)
# define TRACE_S(format,...)
#endif /* TRACE_SIMU */
namespace ns3 {
class SimulatorPrivate {
public:
SimulatorPrivate (Scheduler *events);
~SimulatorPrivate ();
void enable_log_to (char const *filename);
bool is_finished (void) const;
uint64_t next_us (void) const;
void stop (void);
void stop_at_us (uint64_t at);
Event schedule_rel_us (Event event, uint64_t delta);
Event schedule_rel_s (Event event, double delta);
Event schedule_abs_us (Event event, uint64_t time);
Event schedule_abs_s (Event event, double time);
Event remove (Event const ev);
uint64_t now_us (void);
double now_s (void);
void schedule_now (Event event);
void schedule_destroy (Event event);
private:
void process_one_event (void);
typedef std::list<std::pair<Event,uint32_t> > Events;
Events m_destroy;
uint64_t m_stop_at;
bool m_stop;
Scheduler *m_events;
uint32_t m_uid;
uint32_t m_current_uid;
uint64_t m_current_us;
std::ofstream m_log;
std::ifstream m_input_log;
bool m_log_enable;
};
SimulatorPrivate::SimulatorPrivate (Scheduler *events)
{
m_stop = false;
m_stop_at = 0;
m_events = events;
m_uid = 0;
m_log_enable = false;
m_current_us = 0;
}
SimulatorPrivate::~SimulatorPrivate ()
{
while (!m_destroy.empty ()) {
Event ev = m_destroy.front ().first;
m_destroy.pop_front ();
TRACE ("handle destroy " << ev);
ev ();
}
delete m_events;
m_events = (Scheduler *)0xdeadbeaf;
}
void
SimulatorPrivate::enable_log_to (char const *filename)
{
m_log.open (filename);
m_log_enable = true;
}
void
SimulatorPrivate::process_one_event (void)
{
Event next_ev = m_events->peek_next ();
Scheduler::EventKey next_key = m_events->peek_next_key ();
m_events->remove_next ();
TRACE ("handle " << next_ev);
m_current_us = next_key.m_time;
m_current_uid = next_key.m_uid;
if (m_log_enable) {
m_log << "e "<<next_key.m_uid << " " << next_key.m_time << std::endl;
}
next_ev ();
}
bool
SimulatorPrivate::is_finished (void) const
{
return m_events->is_empty ();
}
uint64_t
SimulatorPrivate::next_us (void) const
{
assert (!m_events->is_empty ());
Scheduler::EventKey next_key = m_events->peek_next_key ();
return next_key.m_time;
}
void
SimulatorPrivate::run (void)
{
while (!m_events->is_empty () && !m_stop &&
(m_stop_at == 0 || m_stop_at > next_us ())) {
process_one_event ();
}
m_log.close ();
}
void
SimulatorPrivate::stop (void)
{
m_stop = true;
}
void
SimulatorPrivate::stop_at_us (uint64_t at)
{
m_stop_at = at;
}
Event
SimulatorPrivate::schedule_rel_us (Event event, uint64_t delta)
{
uint64_t current = now_us ();
return schedule_abs_us (event, current+delta);
}
Event
SimulatorPrivate::schedule_abs_us (Event event, uint64_t time)
{
assert (time >= now_us ());
Scheduler::EventKey key = {time, m_uid};
if (m_log_enable) {
m_log << "i "<<m_current_uid<<" "<<now_us ()<<" "
<<m_uid<<" "<<time << std::endl;
}
m_uid++;
return m_events->insert (event, key);
}
uint64_t
SimulatorPrivate::now_us (void)
{
return m_current_us;
}
Event
SimulatorPrivate::schedule_rel_s (Event event, double delta)
{
int64_t delta_us = (int64_t)(delta * 1000000.0);
uint64_t us = now_us () + delta_us;
return schedule_abs_us (event, us);
}
Event
SimulatorPrivate::schedule_abs_s (Event event, double time)
{
int64_t us = (int64_t)(time * 1000000.0);
assert (us >= 0);
return schedule_abs_us (event, (uint64_t)us);
}
double
SimulatorPrivate::now_s (void)
{
double us = m_current_us;
us /= 1000000;
return us;
}
void
SimulatorPrivate::schedule_now (Event event)
{
schedule_abs_us (event, now_us ());
}
void
SimulatorPrivate::schedule_destroy (Event event)
{
m_destroy.push_back (std::make_pair (event, m_uid));
if (m_log_enable) {
m_log << "id " << m_current_uid << " " << now_us () << " "
<< m_uid << std::endl;
}
m_uid++;
}
Event
SimulatorPrivate::remove (Event const ev)
{
Scheduler::EventKey key = m_events->remove (ev);
if (m_log_enable) {
m_log << "r " << m_current_uid << " " << now_us () << " "
<< key.m_uid << " " << key.m_time << std::endl;
}
return Event (ev);
}
}; // namespace ns3
#include "scheduler-list.h"
#include "scheduler-heap.h"
#include "scheduler-map.h"
namespace ns3 {
SimulatorPrivate *Simulator::m_priv = 0;
Simulator::ListType Simulator::m_list_type = LINKED_LIST;
void Simulator::set_linked_list (void)
{
m_list_type = LINKED_LIST;
}
void Simulator::set_binary_heap (void)
{
m_list_type = BINARY_HEAP;
}
void Simulator::set_std_map (void)
{
m_list_type = STD_MAP;
}
void Simulator::enable_log_to (char const *filename)
{
get_priv ()->enable_log_to (filename);
}
SimulatorPrivate *
Simulator::get_priv (void)
{
if (m_priv == 0) {
Scheduler *events;
switch (m_list_type) {
case LINKED_LIST:
events = new SchedulerList ();
break;
case BINARY_HEAP:
events = new SchedulerHeap ();
break;
case STD_MAP:
events = new SchedulerMap ();
break;
default: // not reached
events = 0;
assert (false);
break;
}
m_priv = new SimulatorPrivate (events);
}
TRACE_S ("priv " << m_priv);
return m_priv;
}
void
Simulator::destroy (void)
{
delete m_priv;
m_priv = 0;
}
bool
Simulator::is_finished (void)
{
return get_priv ()->is_finished ();
}
uint64_t
Simulator::next_us (void)
{
return get_priv ()->next_us ();
}
void
Simulator::run (void)
{
get_priv ()->run ();
}
void
Simulator::stop (void)
{
TRACE ("stop");
get_priv ()->stop ();
}
void
Simulator::stop_at_us (uint64_t at)
{
get_priv ()->stop_at_us (at);
}
Event
Simulator::schedule_rel_us (uint64_t delta, Event event)
{
TRACE ("insert " << event << " in " << delta << "us");
return get_priv ()->schedule_rel_us (event, delta);
}
Event
Simulator::schedule_abs_us (uint64_t time, Event event)
{
TRACE ("insert " << event << " at " << time << "us");
return get_priv ()->schedule_abs_us (event, time);
}
uint64_t
Simulator::now_us (void)
{
return get_priv ()->now_us ();
}
Event
Simulator::schedule_rel_s (double delta, Event event)
{
TRACE ("insert " << event << " in " << delta << "s");
return get_priv ()->schedule_rel_s (event, delta);
}
Event
Simulator::schedule_abs_s (double time, Event event)
{
TRACE ("insert " << event << " at " << time << "s");
return get_priv ()->schedule_abs_s (event, time);
}
double
Simulator::now_s (void)
{
return get_priv ()->now_s ();
}
void
Simulator::schedule_now (Event event)
{
TRACE ("insert later " << event);
return get_priv ()->schedule_now (event);
}
void
Simulator::schedule_destroy (Event event)
{
TRACE ("insert at destroy " << event);
return get_priv ()->schedule_destroy (event);
}
Event
Simulator::remove (Event const ev)
{
return get_priv ()->remove (ev);
}
}; // namespace ns3
namespace ns3 {
};