]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/replicalog.cc
update
[l4.git] / l4 / pkg / plr / server / src / fault_handlers / replicalog.cc
1 /*
2  * replicalog.cc --
3  *
4  *     Fault observer that attaches a magic event buffer
5  *     (see measurements.h) to each replica and dumps the replicas'
6  *     event buffers after the program terminates.
7  *
8  * (c) 2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
9  *     economic rights: Technische Universität Dresden (Germany)
10  *
11  * This file is part of TUD:OS and distributed under the terms of the
12  * GNU General Public License 2.
13  * Please see the COPYING-GPL-2 file for details.
14  */
15
16 #include "observers.h"
17 #include "../configuration"
18 #include "../memory"
19 #include "../manager"
20 #include "../log"
21
22 #include <l4/plr/uu.h>
23 #include <l4/plr/measurements.h>
24
25 namespace Romain {
26         extern InstanceManager *_the_instance_manager;
27 }
28
29
30 void *to_thread(void *arg)
31 {
32         Romain::ReplicaLogObserver *o = reinterpret_cast<Romain::ReplicaLogObserver *>(arg);
33         INFO() << "Waiting for " << o->timeout() << " seconds.";
34         sleep(o->timeout());
35
36         if (o->want_cancel())
37                 return NULL;
38
39         l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "romain::timout");
40
41         Measurements::GenericEvent* ev = Romain::_the_instance_manager->logbuf()->next();
42         ev->header.tsc                 = Romain::_the_instance_manager->logbuf()->getTime(Romain::Log::logLocalTSC);
43         ev->header.vcpu                = (l4_uint32_t)0xDEADBEEF;
44         ev->header.type                = Measurements::Thread_stop;
45
46         Romain::_the_instance_manager->show_stats();
47
48         INFO() << "abort";
49
50         enter_kdebug("abort after logdump");
51
52         return NULL;
53 }
54
55
56 Romain::ReplicaLogObserver::ReplicaLogObserver()
57         : _cancel(false)
58 {
59         _timeout = ConfigIntValue("general:logtimeout");
60         if (_timeout > 0) {
61                 int err = pthread_create(&_to_thread, NULL, to_thread, this);
62                 _check(err != 0, "error creating timeout thread");
63         }
64         for (unsigned i = 0; i < Romain::MAX_REPLICAS; ++i) {
65                 buffers[i].local_addr = 0;
66         }
67 }
68
69
70 void
71 Romain::ReplicaLogObserver::map_eventlog(Romain::App_instance *i, int logsizeMB)
72 {
73         int size = logsizeMB << 20;
74         unsigned mapops = 0;
75         l4_addr_t local_map_addr = buffers[i->id()].local_addr;
76         l4_addr_t remote_map_addr = Romain::REPLICA_LOG_ADDRESS;
77
78         /* 1. map the TSC shared page read-only */
79         INFO() << "shared tsc @ " << Romain::_the_instance_manager->logbuf()->timestamp;
80         i->map_aligned(reinterpret_cast<l4_addr_t>(Romain::_the_instance_manager->logbuf()->timestamp),
81                        Romain::REPLICA_TSC_ADDRESS, L4_PAGESHIFT, L4_FPAGE_RO);
82
83         /* Now initialize the shared event buffer */
84         Measurements::EventBuf* buf = reinterpret_cast<Measurements::EventBuf*>(buffers[i->id()].local_addr);
85         buf->index = 0;
86         buf->sharedTSC = true;
87         buf->set_buffer((unsigned char*)remote_map_addr + sizeof(Measurements::GenericEvent), (logsizeMB << 20) - sizeof(Measurements::GenericEvent));
88         INFO() << buf->index << " " << buf->size << std::endl;
89
90         while (size > 0) {
91
92                 unsigned sz, shift;
93
94                 if (size >= (4 << 20)) { // map 4 MB page
95                         sz = L4_SUPERPAGESIZE;
96                         shift = L4_SUPERPAGESHIFT;
97                 } else { // map 4 kB page
98                         sz = L4_PAGESIZE;
99                         shift = L4_PAGESHIFT;
100                 }
101
102                 i->map_aligned(local_map_addr, remote_map_addr, shift, L4_FPAGE_RW);
103                 size            -= sz;
104                 local_map_addr  += sz;
105                 remote_map_addr += sz;
106                 mapops          += 1;
107         }
108
109         INFO() << "Mapped to replica. Used " << mapops << " map() operations";
110 }
111
112
113 void Romain::ReplicaLogObserver::startup_notify(Romain::App_instance *i,
114                                                                     Romain::App_thread *t,
115                                                                     Romain::Thread_group *tg,
116                                                                     Romain::App_model *a)
117 {
118         static bool logregion_reserved = false;
119
120         int logMB = ConfigIntValue("general:replicalogsize");
121         if (logMB == -1) { // use general logbuf size if no specific size was set
122                 logMB = ConfigIntValue("general:logbuf");
123         }
124
125         INFO() << "Replica log size: " << logMB << " MB";
126
127         /* Reserve the area at the replicas' RM. We map this buffer without going through
128            the official channels. */
129         if (!logregion_reserved) {
130                 a->rm()->attach_area(Romain::REPLICA_LOG_ADDRESS, logMB << 20, 0, L4_SUPERPAGESHIFT);
131                 logregion_reserved = true;
132         }
133
134         L4::Cap<L4Re::Dataspace> mem;
135         buffers[i->id()].local_addr = Romain::Region_map::allocate_and_attach(&mem, logMB << 20, 0, L4_SUPERPAGESHIFT);
136         INFO() << "Buffer for instance " << i->id() << " @ " << std::hex << buffers[i->id()].local_addr;
137         l4_touch_rw(reinterpret_cast<void*>(buffers[i->id()].local_addr), logMB << 20);
138
139         map_eventlog(i, logMB);
140
141         //enter_kdebug("LogObserver::startup");
142 }
143
144
145 Romain::Observer::ObserverReturnVal
146 Romain::ReplicaLogObserver::notify(Romain::App_instance *i,
147                                    Romain::App_thread *t,
148                                    Romain::Thread_group *tg,
149                                    Romain::App_model *a)
150 {
151         /* We don't handle any events. */
152         return Romain::Observer::Ignored;
153 }
154
155
156 void
157 Romain::ReplicaLogObserver::dump_eventlog(unsigned id) const
158 {
159         // prevent a potential timeout thread from dumping in parallel
160         const_cast<Romain::ReplicaLogObserver*>(this)->_cancel = true;
161
162         INFO() << "Dumping ... " << id;
163
164         Measurements::EventBuf *buf = reinterpret_cast<Measurements::EventBuf*>(buffers[id].local_addr);
165         INFO() << "  event buffer @ " << std::hex << buf;
166
167         char filename[32];
168         snprintf(filename, 32, "replica%d.log", id);
169
170         INFO() << "file: " << filename;
171
172         unsigned oldest = buf->oldest();
173
174         INFO() << "oldest: " << oldest;
175
176         l4_umword_t dump_start, dump_size;
177         if (!oldest) {
178                 dump_start = 0;
179                 dump_size  = buf->index * sizeof(Measurements::GenericEvent);
180         } else {
181                 dump_start = oldest * sizeof(Measurements::GenericEvent);
182                 dump_size  = buf->size * sizeof(Measurements::GenericEvent);
183         }
184
185         /* buf addr is relocated in replica AS -> need to retransform */
186         char *bufaddr = ((l4_addr_t)buf->buffer - Romain::REPLICA_LOG_ADDRESS) + (char*)buf;
187
188         INFO() << "file: " << filename << " start " << std::hex << dump_start << " size " << dump_size;
189         uu_dumpz_ringbuffer(filename, bufaddr,
190                             buf->size * sizeof(Measurements::GenericEvent),
191                             dump_start, dump_size);
192 }
193
194
195 void
196 Romain::ReplicaLogObserver::status() const
197 {
198         for (unsigned i = 0; i < Romain::MAX_REPLICAS; ++i) {
199                 if (buffers[i].local_addr != 0) {
200                         dump_eventlog(i);
201                 }
202         }
203         //enter_kdebug("LogObserver::status");
204 }