]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/replicalog.cc
2371c840dab94b3af5a2487e62518c77685db41d
[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         Measurements::GenericEvent* ev = Romain::_the_instance_manager->logbuf()->next();
40         ev->header.tsc                 = Romain::_the_instance_manager->logbuf()->getTime(Romain::Log::logLocalTSC);
41         ev->header.vcpu                = (l4_uint32_t)0xDEADBEEF;
42         ev->header.type                = Measurements::Thread_stop;
43
44         Romain::_the_instance_manager->show_stats();
45
46         INFO() << "abort";
47
48         enter_kdebug("abort after logdump");
49
50         return NULL;
51 }
52
53
54 Romain::ReplicaLogObserver::ReplicaLogObserver()
55         : _cancel(false)
56 {
57         _timeout = ConfigIntValue("general:logtimeout");
58         if (_timeout > 0) {
59                 int err = pthread_create(&_to_thread, NULL, to_thread, this);
60                 _check(err != 0, "error creating timeout thread");
61         }
62         for (unsigned i = 0; i < Romain::MAX_REPLICAS; ++i) {
63                 buffers[i].local_addr = 0;
64         }
65 }
66
67
68 void
69 Romain::ReplicaLogObserver::map_eventlog(Romain::App_instance *i, int logsizeMB)
70 {
71         int size = logsizeMB << 20;
72         unsigned mapops = 0;
73         l4_addr_t local_map_addr = buffers[i->id()].local_addr;
74         l4_addr_t remote_map_addr = Romain::REPLICA_LOG_ADDRESS;
75
76         /* 1. map the TSC shared page read-only */
77         INFO() << "shared tsc @ " << Romain::_the_instance_manager->logbuf()->timestamp;
78         i->map_aligned(reinterpret_cast<l4_addr_t>(Romain::_the_instance_manager->logbuf()->timestamp),
79                        Romain::REPLICA_TSC_ADDRESS, L4_PAGESHIFT, L4_FPAGE_RO);
80
81         /* Now initialize the shared event buffer */
82         Measurements::EventBuf* buf = reinterpret_cast<Measurements::EventBuf*>(buffers[i->id()].local_addr);
83         buf->index = 0;
84         buf->sharedTSC = true;
85         buf->set_buffer((unsigned char*)remote_map_addr + sizeof(Measurements::GenericEvent), (logsizeMB << 20) - sizeof(Measurements::GenericEvent));
86         INFO() << buf->index << " " << buf->size << std::endl;
87
88         while (size > 0) {
89
90                 unsigned sz, shift;
91
92                 if (size >= (4 << 20)) { // map 4 MB page
93                         sz = L4_SUPERPAGESIZE;
94                         shift = L4_SUPERPAGESHIFT;
95                 } else { // map 4 kB page
96                         sz = L4_PAGESIZE;
97                         shift = L4_PAGESHIFT;
98                 }
99
100                 i->map_aligned(local_map_addr, remote_map_addr, shift, L4_FPAGE_RW);
101                 size            -= sz;
102                 local_map_addr  += sz;
103                 remote_map_addr += sz;
104                 mapops          += 1;
105         }
106
107         INFO() << "Mapped to replica. Used " << mapops << " map() operations";
108 }
109
110
111 void Romain::ReplicaLogObserver::startup_notify(Romain::App_instance *i,
112                                                                     Romain::App_thread *t,
113                                                                     Romain::Thread_group *tg,
114                                                                     Romain::App_model *a)
115 {
116         static bool logregion_reserved = false;
117
118         int logMB = ConfigIntValue("general:replicalogsize");
119         if (logMB == -1) { // use general logbuf size if no specific size was set
120                 logMB = ConfigIntValue("general:logbuf");
121         }
122
123         INFO() << "Replica log size: " << logMB << " MB";
124
125         /* Reserve the area at the replicas' RM. We map this buffer without going through
126            the official channels. */
127         if (!logregion_reserved) {
128                 a->rm()->attach_area(Romain::REPLICA_LOG_ADDRESS, logMB << 20, 0, L4_SUPERPAGESHIFT);
129                 logregion_reserved = true;
130         }
131
132         L4::Cap<L4Re::Dataspace> mem;
133         buffers[i->id()].local_addr = Romain::Region_map::allocate_and_attach(&mem, logMB << 20, 0, L4_SUPERPAGESHIFT);
134         INFO() << "Buffer for instance " << i->id() << " @ " << std::hex << buffers[i->id()].local_addr;
135         l4_touch_rw(reinterpret_cast<void*>(buffers[i->id()].local_addr), logMB << 20);
136
137         map_eventlog(i, logMB);
138
139         //enter_kdebug("LogObserver::startup");
140 }
141
142
143 Romain::Observer::ObserverReturnVal
144 Romain::ReplicaLogObserver::notify(Romain::App_instance *i,
145                                    Romain::App_thread *t,
146                                    Romain::Thread_group *tg,
147                                    Romain::App_model *a)
148 {
149         /* We don't handle any events. */
150         return Romain::Observer::Ignored;
151 }
152
153
154 void
155 Romain::ReplicaLogObserver::dump_eventlog(unsigned id) const
156 {
157         // prevent a potential timeout thread from dumping in parallel
158         const_cast<Romain::ReplicaLogObserver*>(this)->_cancel = true;
159
160         INFO() << "Dumping ... " << id;
161
162         Measurements::EventBuf *buf = reinterpret_cast<Measurements::EventBuf*>(buffers[id].local_addr);
163         INFO() << "  event buffer @ " << std::hex << buf;
164
165         char filename[32];
166         snprintf(filename, 32, "replica%d.log", id);
167
168         INFO() << "file: " << filename;
169
170         unsigned oldest = buf->oldest();
171
172         INFO() << "oldest: " << oldest;
173
174         l4_umword_t dump_start, dump_size;
175         if (!oldest) {
176                 dump_start = 0;
177                 dump_size  = buf->index * sizeof(Measurements::GenericEvent);
178         } else {
179                 dump_start = oldest * sizeof(Measurements::GenericEvent);
180                 dump_size  = buf->size * sizeof(Measurements::GenericEvent);
181         }
182
183         /* buf addr is relocated in replica AS -> need to retransform */
184         char *bufaddr = ((l4_addr_t)buf->buffer - Romain::REPLICA_LOG_ADDRESS) + (char*)buf;
185
186         INFO() << "file: " << filename << " start " << std::hex << dump_start << " size " << dump_size;
187         uu_dumpz_ringbuffer(filename, bufaddr,
188                             buf->size * sizeof(Measurements::GenericEvent),
189                             dump_start, dump_size);
190 }
191
192
193 void
194 Romain::ReplicaLogObserver::status() const
195 {
196         for (unsigned i = 0; i < Romain::MAX_REPLICAS; ++i) {
197                 if (buffers[i].local_addr != 0) {
198                         dump_eventlog(i);
199                 }
200         }
201         //enter_kdebug("LogObserver::status");
202 }