├── .gitignore
├── AUTHORS
├── ChangeLog
├── LICENSE
├── Makefile.am
├── NEWS
├── README
├── README.md
├── TODO.txt
├── cleanup.sh
├── configure.ac
├── examples
├── hello
│ ├── hello.cc
│ └── makefile
└── interact
│ ├── Makefile.am
│ └── example.c
├── liblog2mem
├── Makefile.am
├── log2mem.c
├── log2mem
│ ├── log2mem.h
│ └── log2mem_dev.h
├── log2mem_atomic.h
└── log2mem_atomic_gcc.h
├── qtgui
├── Makefile
├── Makefile.am
├── appman.cpp
├── appman.h
├── example1.pro
├── example1.pro.user
├── example1.pro.user.3.2-pre1
├── images
│ ├── copy.png
│ ├── cut.png
│ ├── new.png
│ ├── open.png
│ ├── paste.png
│ └── save.png
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── resources.qrc
├── tablemodel.cpp
└── tablemodel.h
├── setup.sh
└── util
├── Makefile.am
└── log2memutil.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # http://www.gnu.org/software/automake
2 |
3 | Makefile.in
4 |
5 | # http://www.gnu.org/software/autoconf
6 |
7 | /autom4te.cache
8 | /aclocal.m4
9 | /compile
10 | /configure
11 | /depcomp
12 | /install-sh
13 | /missing
14 | /stamp-h1
15 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Darren Smith
2 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/ChangeLog
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | log2mem -- C/C++ low-latency lightweight memory mapped diagnostic logger
635 | Copyright (C) 2013 Darren Smith
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | log2mem Copyright (C) 2013 Darren Smith
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | # The ACLOCAL_AMFLAGS variable is a requirement of using a macro
2 | # sub-directory. According to the Automake documentation, this variable should
3 | # be defined in the top-level Makefile.am file of any project that uses
4 | # AC_CONFIG_MACRO_DIR in its configure.ac file. These flags indicate to
5 | # aclocal where it should look for macro files when it's executed by rules
6 | # defined in Makefile.am.
7 | ACLOCAL_AMFLAGS = -I m4
8 |
9 | SUBDIRS = @DIRS@
10 |
11 |
--------------------------------------------------------------------------------
/NEWS:
--------------------------------------------------------------------------------
1 |
2 |
3 | 11/08/13 - Version 1.0
4 | ----------------------
5 |
6 | Initial prototype version
7 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/README
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | log2mem
2 | =======
3 |
4 | log2mem is a high-performance diagnostic C/C++ logger designed to serve as a
5 | debugging tool when dealing with bugs and race conditions in multi-threaded or
6 | low latency code.
7 |
8 | Most developers are familer with the two basic approachs to debugging: execute
9 | the code in a debugger; or litter the source with increasingly targeted and
10 | detailed printf/std::cout statements. However for multit-hreaded or low latency
11 | code, both approaches often fail to work.
12 |
13 | The problem is time. Whether or not a bug gets triggered can be dependent on not
14 | just a program's inputs but also on its run-time speed and how important threads
15 | interact with one another. Stepping through the code with a debugger (such as
16 | gdb) will significantly reduce execution speed. So if a bug only arises when
17 | its threads interact at normal speed, then slowing down the program typically
18 | supresses the bug. Similarly printf/std::cout statements have a cost; strings
19 | are constructed and written to an output stream, and these too impede program
20 | speed. The developer is left with the frustrating and not uncommon conundrum
21 | that the act of debugging a bug causes it to temporarily disappear.
22 |
23 | The excellent blog *Preshing on Programming* also identifies this problem of
24 | debugging multi-threaded code, and log2mem is inspired by the solution described
25 | there. [Lightweight In-Memory Logging, 22 May 2012,
26 | http://preshing.com/20120522/lightweight-in-memory-logging]
27 |
28 | Additionally for some classes of program typically characterised as low latency
29 | or real-time, proper program execution is dependent on it running at normal
30 | speed (e.g. software for robot contro or processing live finanical market data).
31 | So any runtime slow introduced by debugging techniques might not even allow for
32 | correct functionality, let alone tickling the bug into appearence.
33 |
34 | Use of application specific asynchronous loggers is sometimes an option. However
35 | they are often not designed or implemented with low latency in mind (e.g. they
36 | typically build strings), and so again their usage can adveresly impact program
37 | speed. Such loggers might not be readily accesible at the code site being
38 | examined, so even trying to use them can be painful.
39 |
40 | What does log2mem offer?
41 | ------------------------
42 |
43 | log2mem is a tool to use for these situations when a debugger and printf
44 | somewhat sturggle. It offers the rough equivalent of very high speed printf;
45 | this can then be used to instrument the code without comprimsing runtime
46 | performance. The program can be run at full speed, the bug can arise, and its
47 | footprints can be logged.
48 |
49 | log2mem acheives high performance (typically around 100 to 150 nanoseconds per
50 | call) by writing log statements to a circular buffer held in shared memory. So
51 | whereas printf involves string construction and writing to some kind of stream
52 | at the time of the call, log2mem instead writes the raw data values direct to
53 | in-memory circular buffer. A separate tool, log2mem-util, is later used to
54 | inspect the shared memory and convert the raw logging data to human readable
55 | strings. log2mem additionally makes use of lock-free techniques to ensure
56 | optimal performance. Additionally, log2mem is easy to integrate in existing
57 | C/C++ code.
58 |
59 | Note that the ciruclar bufffer is pre-defined to store a fixed amount of data.
60 | Once that limit is reached, new messages can continue to be stored, but they
61 | will overwrite the oldest messages. Given this limitation, log2mem is not
62 | particularly suitable for general application logging.
63 |
64 | Hello World
65 | ===========
66 |
67 | Below is a basic "hello world" example of using log2mem. Integration into
68 | application code requires that the header file `log2mem.h` is included and the
69 | library `liblog2mem` added to the link line.
70 |
71 | ```c++
72 | #include
73 | #include
74 |
75 | int main(int, char**)
76 | {
77 | std::cout << "hello world" << std::endl;
78 |
79 | // obtain a logging row, and write a simple message & value
80 | void * rowptr = log2mem_get_row(MEMLOGFL);
81 | log2mem_append_str2(rowptr, "hello world");
82 | log2mem_append_int(rowptr, 100);
83 |
84 | // print location of the memmap
85 | std::cout << "log2mem memmap: " << log2mem_filename() << std::endl;
86 | return 0;
87 | }
88 | ```
89 |
90 | This could be complied with the following kind of command, which needs to
91 | specify the location where log2mem has been installed.
92 |
93 | g++ -I/tmp/log2mem/include hello.cc -o hello -L/tmp/log2mem/lib -llog2mem
94 |
95 | This assumes that, when log2mem was build, it was installed into /tmp/log2mem.
96 | If different install location was used, then the compile command should be
97 | changed appropriately.
98 |
99 | The logging statements can be displayed by using the log2mem-util:
100 |
101 | $ util/log2mem-util /var/tmp/log2mem-darrens.dat
102 | 0 [31224] (hello.cc:9) hello world 100
103 |
104 |
105 | Variables & external interaction
106 | ================================
107 |
108 | In addition to diagnositc logging, log2mem offers and additiional feature to
109 | assist debugging. The API can be used to define variables that get stored in the
110 | memmap, and which can be read and written both by the application code and by
111 | the external log2mem-util. This provides a quick & easy mechanism to enable a
112 | developer to interact with a program while it is being debugged (e.g., to
113 | temporarily alter its course of execution, or read & write program state). The
114 | traditional approach to achieve this, outside of a debugger, is to use posix
115 | signals.
116 |
117 | The following code shows how to create a variable nd how to access it from
118 | outside the debugged program:
119 |
120 | // create int variable, give it a name & id, and set to 0
121 | int var_id = 1;
122 | const char* var_name = "stopflag";
123 | log2mem_var_int_init(var_id, 0, var_name);
124 |
125 | # externally set variable to 1
126 | $ log2mem-util /tmp/log2mem.dat --int[1]=1
127 |
128 |
129 |
--------------------------------------------------------------------------------
/TODO.txt:
--------------------------------------------------------------------------------
1 | log2mem
2 | =======
3 |
4 | List of next features
5 | =====================
6 |
7 | * build a QT based GUI for interacting with the memmap
8 |
9 | * support atomics on i386 targets (should work on Suse 9.3, which lacks atomics)
10 |
11 | * review the output format, is it acceptabile? E.g., current the date is not
12 | presnet.
13 |
14 | * implement filename selection (see TODOs). review the choice of default
15 | filename. Is it really /tmp/log2mem.dat? If so, it will cause a lot of
16 | runtime problems when the file cannot be created.
17 |
18 | * support a logging daemon; allow tailing of memmap contents
19 |
20 | * benchmarking: can I find out how long it takes to perform a logging operation?
21 |
22 | * when the global handle is first obtained, maybe store the program pid
23 | there, so that we can also print the pid on each line (together with the
24 | lwp).
25 |
26 | * log2mem should dump the time as the first item on the line
27 |
28 | * maybe add a timestamp in the header, to show when last updated ... this is so
29 | that we can see if the application is moving
30 |
31 | * in xdumptool, at startup, check the arch of the memmap, to see if it is
32 | compatible.
33 |
34 | * try to use, as much as possible, values from the memmap, when building
35 | pointers.
36 |
37 | * try to find the GC macro needed to enable the atomi_gnu include
38 |
39 | * find where I am using _LP, and instead, if it is in a printf, use the PRI
40 | macros instead.
41 |
42 | * decide whether to keep the logging ... instead, could optionally do printf,
43 | if configured to do so
44 |
45 | * provide functions to assoicate names with thread ids (how to do maps in C?)
46 |
47 | * allow the dump tool to colourize differnent threads (how to do maps in C?)
48 |
49 | * review whether we need to have mem_seq_cst orders on the atomic ints... not
50 | sure if we do, because we are not two shared variables.
51 |
52 | * provide an atomic incr for unsigned int
53 |
54 | * change counter type to unsigned int, and wrap in atomic_uint
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | find . -name Makefile.in -exec rm -f '{}' \;
4 |
5 | [ -d m4 ] && rm -rf m4
6 |
7 | for f in depcomp missing INSTALL install-sh config.sub config.guess compile \
8 | config.h.in configure aclocal.m4 configure aclocal.m4 ltmain.sh ar-lib \
9 | autom4te.cache COPYING
10 | do
11 | [ -d "$f" ] && rm -rf "$f"
12 | rm -f "$f"
13 | done
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 |
2 | #========== Initialisation ==========
3 |
4 | AC_INIT([log2mem], [1.1], [log2mem@darrenjs.net], [log2mem], [ ] )
5 | AC_PREREQ([2.59])
6 |
7 | # This macro causes the environment variables, $host, $build and $target to be
8 | # defined.
9 | AC_CANONICAL_SYSTEM
10 |
11 | # Not: the -Wall here is for automake errors; is unrelated to gcc errors
12 | AM_INIT_AUTOMAKE([1.10 no-define -Wall])
13 | AM_PROG_AR
14 |
15 | AC_CONFIG_HEADERS([config.h])
16 | AC_PROG_CXX
17 | AC_CONFIG_MACRO_DIR([m4])
18 |
19 |
20 | # initialise libtool support
21 |
22 | LT_PREREQ([2.4.2]) # not 'technically' required, but good practice.
23 |
24 | # Note: we initialise libtool with shared-libraries disabled. This makes it
25 | # easier to quickly use log2mem; the user doesn't need to worry about altering
26 | # the LD_LIBRARY_PATH at runtime to pick up liblog2mem.so
27 | LT_INIT([disable-shared])
28 |
29 | #========== Checks for programs ==========
30 |
31 | AC_PROG_CXX
32 | AC_PROG_CC
33 | AM_PROG_LIBTOOL
34 | AC_PROG_INSTALL
35 |
36 |
37 | #========== Check for third party libraries ==========
38 |
39 |
40 | dnl PKG_CHECK_MODULES(QT4, [QtCore QtGui >= 4.4.0], [
41 | dnl AC_PATH_PROGS(MOC, [moc-qt4 moc], moc,`eval $PKG_CONFIG --variable=exec_prefix QtCore`/bin)
42 | dnl AC_PATH_PROG(RCC, rcc, rcc,`eval $PKG_CONFIG --variable=exec_prefix QtCore`/bin)
43 | dnl AC_PATH_PROGS(UIC, [uic-qt4 uic], uic,`eval $PKG_CONFIG --variable=exec_prefix QtCore`/bin)
44 | dnl ], [
45 | dnl AC_MSG_ERROR([Qt 4 library not found])
46 | dnl ])
47 |
48 |
49 | dnl PKG_CHECK_MODULES([QT], [QtCore QtGui Qt3D
50 | dnl ], [
51 | dnl ])
52 |
53 | #========== Checks for header files ==========
54 |
55 | AC_HEADER_STDC
56 | AC_CHECK_HEADERS([errno.h fcntl.h stdint.h stdio.h stdlib.h string.h time.h unistd.h sys/time.h sys/stat.h sys/syscall.h sys/mman.h sys/stat.h sys/types.h ])
57 |
58 | AC_HEADER_STDBOOL
59 | AC_C_CONST
60 | AC_C_INLINE
61 |
62 |
63 | #========== Check functions ==========
64 |
65 |
66 | AC_LINK_IFELSE([AC_LANG_SOURCE([
67 | #ifndef _GNU_SOURCE
68 | #define _GNU_SOURCE
69 | #endif
70 | #include
71 | int main(void) {
72 | char *c;
73 | return __sync_add_and_fetch(c, 1);
74 | }])],[has___sync_add_and_fetch=yes])
75 | if test "x$has___sync_add_and_fetch" = xyes; then
76 | AC_DEFINE(HAVE___SYNC_ADD_AND_FETCH,1,[Define to 1 if you have the __sync_add_and_fetch gcc builtin function])
77 | AC_MSG_RESULT(yes)
78 | else
79 | AC_MSG_RESULT(no)
80 | fi
81 |
82 |
83 |
84 |
85 | #========== User options ==========
86 |
87 | export DIRS="liblog2mem util examples/interact"
88 | extrabuild=
89 | dnl QT option
90 | AC_ARG_ENABLE([gui],
91 | AS_HELP_STRING([--enable-gui], [Enable QT gui]))
92 |
93 | AS_IF([test "x$enable_gui" = "xyes"], [
94 |
95 | DIRS="$DIRS qtgui"
96 | ])
97 | #========== Generation ==========
98 |
99 | AC_SUBST(DIRS)
100 |
101 | # List the files that will be generated. These are mainly makefiles, which
102 | # automake will generate from the corresponding Makefile.am
103 | AC_CONFIG_FILES([
104 | Makefile
105 | liblog2mem/Makefile
106 | util/Makefile
107 | examples/interact/Makefile
108 | qtgui/Makefile
109 | ])
110 |
111 | # Trigger the generation of our makefiles
112 | AC_OUTPUT
113 |
114 |
115 |
--------------------------------------------------------------------------------
/examples/hello/hello.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int, char**)
5 | {
6 | std::cout << "hello world" << std::endl;
7 |
8 | // obtain a logging row, and write a simple message & va
9 | void * rowptr = log2mem_get_row(MEMLOGFL);
10 | log2mem_append_str(rowptr, "hello world");
11 | log2mem_append_int(rowptr, 100);
12 |
13 | std::cout << "log2mem memmap: " << log2mem_filename() << std::endl;
14 | return 0;
15 | }
16 |
--------------------------------------------------------------------------------
/examples/hello/makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 |
3 | # edit to specify where the log2mem build was installed
4 | LOG2MEMDIR=/var/tmp/log2mem
5 |
6 | hello: hello.cc
7 | ${CXX} -I$(LOG2MEMDIR)/include -o hello hello.cc -L$(LOG2MEMDIR)/lib -llog2mem
8 |
9 | clean:
10 | rm -f hello
--------------------------------------------------------------------------------
/examples/interact/Makefile.am:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # NOTE: it is not good practice to add "-Wall" and "-03" etc here. Those
5 | # choices should be made by the user when they invoke the configure script.
6 | AM_CPPFLAGS = -I$(top_srcdir)/liblog2mem -Wall -pthread
7 |
8 | # NOTE: -lrt added for posix clock support
9 | AM_LDFLAGS=-L$(top_builddir)/liblog2mem -llog2mem -lrt -pthread
10 |
11 | noinst_PROGRAMS=example
12 | #noinst_PROGRAMS=server_demo
13 |
14 |
15 | example_SOURCES=example.c
16 |
17 |
--------------------------------------------------------------------------------
/examples/interact/example.c:
--------------------------------------------------------------------------------
1 |
2 |
3 | #include "log2mem/log2mem.h"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #define MEMMAPFILE_SWITCH "--memmapfile"
14 | #define HELP_SWITCH "--help"
15 |
16 |
17 | const char* timestamp()
18 | {
19 | static char lbuf[100] = {'\0', '\0'};
20 |
21 | // get current time
22 | struct timeval now;
23 | struct timezone * const tz = NULL; /* not used on Linux */
24 | gettimeofday(&now, tz);
25 |
26 | // break time down into parts
27 | struct tm _tm;
28 | localtime_r(&now.tv_sec, &_tm);
29 |
30 |
31 | snprintf(lbuf, sizeof(lbuf)-1, "gettimeofday %02li.%09li",
32 | now.tv_sec, now.tv_usec*1000);
33 |
34 | return lbuf;
35 | }
36 |
37 | const char* posix_timestamp(clockid_t clk_id, const char* s)
38 | {
39 | static char lbuf[100] = {'\0', '\0'};
40 | struct timespec tp;
41 |
42 | if (!clock_gettime(clk_id, &tp))
43 | {
44 | snprintf(lbuf, sizeof(lbuf)-1, "clock_gettime %s %02li.%09li", s,
45 | tp.tv_sec,
46 | tp.tv_nsec);
47 | }
48 | return lbuf;
49 | }
50 |
51 |
52 | void loop(const char* s)
53 | {
54 | log2mem_write("starting loop", __FILE__, __LINE__);
55 |
56 | /* void * rowptr = log2mem_get_row(__FILE__, __LINE__); */
57 | /* log2mem_append_str(rowptr, "loop name:", 10); */
58 | /* log2mem_append_str(rowptr, s, strlen(s)); */
59 |
60 | float f = 1.1;
61 | int i = 0;
62 |
63 | int iterations = 0;
64 | for (i = 0; i < 50; ++i)
65 | {
66 | f += 1.12;
67 | // log2mem_write(s,__FILE__, __LINE__);
68 | struct timeval tv;
69 | gettimeofday(&tv, 0);
70 |
71 | long l = tv.tv_sec*1000000+tv.tv_usec;
72 |
73 | void* rowptr = log2mem_get_row(MEMLOGFL);
74 | log2mem_append_long(rowptr, l);
75 |
76 | log2mem_var_double_set(i & 0x7, f);
77 |
78 | log2mem_counter_incr(0);
79 |
80 | iterations++;
81 | }
82 | log2mem_write("ending loop", MEMLOGFL);
83 |
84 |
85 | sleep(4);
86 | void * rowptr = log2mem_get_row(__FILE__, __LINE__);
87 | log2mem_append_str(rowptr, "loop name:");
88 | log2mem_append_str(rowptr, s);
89 | log2mem_append_str(rowptr, "completed after");
90 | log2mem_append_int(rowptr, iterations);
91 | log2mem_append_str(rowptr, "iterations");
92 |
93 | }
94 |
95 |
96 |
97 | void flow1(int idoffset)
98 | {
99 | int i = 0;
100 | for (; i < 1000; ++i)
101 | {
102 | int id = idoffset + i*10;
103 |
104 | log2mem_ts t0 = log2mem_time();
105 | log2mem_ts t1 = log2mem_time();
106 | log2mem_ts t2 = log2mem_time();
107 | log2mem_ts t3 = log2mem_time();
108 |
109 | /* time logging of an initial pre-sequence */
110 | log2mem_time_event3(0, id, "preseq_beg");
111 | log2mem_time_event2(0, id);
112 | log2mem_time_event2(0, id);
113 | log2mem_time_event3(0, id, "preseq_end");
114 |
115 | /* pre-sequence now gives way to the loop of sub-sequences. */
116 | int j;
117 | for (j=0; j < 3; ++j)
118 | {
119 |
120 | log2mem_counter_incr(0);
121 |
122 | void* row = log2mem_time_event3(1, id+j, "subseq_beg");
123 |
124 | /* log the ID of the preseq*/
125 | log2mem_append_str(row, "preseqid");
126 | log2mem_append_str(row, "XXYYZZ");
127 | log2mem_append_int(row, id);
128 |
129 | log2mem_time_event2(1, id+j);
130 | log2mem_time_event2(1, id+j);
131 | log2mem_time_event2(1, id+j);
132 | log2mem_time_event3(1, id+j, "subseq_end");
133 | }
134 |
135 | log2mem_time_event3(0, id, "fullseq_end");
136 |
137 | log2mem_set_ts( log2mem_time_event3(2, 0, "t0"), t0 );
138 | log2mem_set_ts( log2mem_time_event3(2, 1, "t1"), t1 );
139 | log2mem_set_ts( log2mem_time_event3(2, 2, "t2"), t2 );
140 | log2mem_set_ts( log2mem_time_event3(2, 3, "t3"), t3 );
141 | log2mem_set_ts( log2mem_time_event3(2, 3, "t3"), t3 );
142 |
143 | int k = 0;
144 | for (k = 0; k < 3; ++k)
145 | {
146 | void* r = log2mem_time_event3(0, id, "TEST");
147 |
148 | log2mem_append_str(r, "example_string");
149 | log2mem_append_str2(r, "str2", 4);
150 | log2mem_append_int(r, -1024);
151 | log2mem_append_uint(r, +1024);
152 | log2mem_append_long(r, -92233720368547758UL);
153 | log2mem_append_ulong(r, 9223372036854775807);
154 | log2mem_append_float(r, 1.1);
155 | log2mem_append_double(r, 1234.0000001);
156 | log2mem_append_char(r, 'x');
157 | log2mem_time_event3(0, id, "POST");
158 | }
159 |
160 | // usleep(500000 + idoffset);
161 | }
162 | }
163 |
164 | //----------------------------------------------------------------------
165 |
166 | void *THREAD_A_main(void *arg)
167 | {
168 | loop("A");
169 | return NULL;
170 | }
171 | void *THREAD_B_main(void *arg)
172 | {
173 | loop("B");
174 | return NULL;
175 | }
176 | void *THREAD_C_main(void *arg)
177 | {
178 | flow1(200000);
179 | return NULL;
180 | }
181 | void *THREAD_D_main(void *arg)
182 | {
183 | flow1(10000);
184 | return NULL;
185 | }
186 |
187 |
188 |
189 | //----------------------------------------------------------------------
190 | void help()
191 | {
192 | printf("log2mem example progam\n\n");
193 | printf("Options\n");
194 | printf(" " MEMMAPFILE_SWITCH " - memory mapped file to create. If not provided, will use default name.\n");
195 | printf(" " HELP_SWITCH " - display help\n");
196 | exit(0);
197 | }
198 |
199 | //----------------------------------------------------------------------
200 | void die(const char* arg)
201 | {
202 | printf("%s\n", arg);
203 | exit(1);
204 | }
205 |
206 | //----------------------------------------------------------------------
207 | int main(int argc, char** argv)
208 | {
209 | const char* user_filename = 0;
210 | int i;
211 |
212 | printf ("argc: %d\n", argc);
213 |
214 | for (i = 1; i < argc; i++)
215 | {
216 | if (strcmp(argv[i], MEMMAPFILE_SWITCH)==0)
217 | {
218 | i++;
219 | if (i>=argc) die("missing arg for option " MEMMAPFILE_SWITCH);
220 | user_filename = argv[i];
221 | }
222 | else if (strcmp(argv[i], HELP_SWITCH)==0)
223 | {
224 | help();
225 | }
226 | else
227 | {
228 | die("unknown option");
229 | }
230 | }
231 |
232 | printf("=== log2mem example program ===\n");
233 |
234 |
235 | if (user_filename)
236 | {
237 | struct log2mem_config config;
238 | memset(&config, 0, sizeof(struct log2mem_config));
239 |
240 | // add MEMLOG_THREADID to collect thread-id
241 | config.options |= MEMLOG_THREADID;
242 |
243 | // add MEMLOG_FILELINE to collect the file and line
244 | config.options |= MEMLOG_FILELINE;
245 |
246 | //config.options |= MEMLOG_GETTIMEOFDAY;
247 | //config.options |= MEMLOG_RDTSC;
248 | config.options |= MEMLOG_CLOCKGETTIME;
249 |
250 | config.num_counters=8;
251 | config.num_rows=1020;
252 | config.row_len=160;
253 | config.num_vars=10;
254 |
255 | printf("initialising log2mem memmap '%s'\n", user_filename);
256 | log2mem_init(user_filename, &config, sizeof(config));
257 | }
258 | else
259 | {
260 | printf("using memmap default initialisation (instead of explicit initialisation)\n");
261 | }
262 |
263 | printf("log2mem status: %s\n", (log2mem_valid()? "ok":"bad"));
264 | if (!log2mem_valid())
265 | {
266 | printf("log2mem could not be initialised ... exiting\n");
267 | exit(1);
268 | }
269 |
270 | printf("log2mem memmap filename: '%s'\n", log2mem_filename());
271 |
272 | printf("logging some rows\n");
273 |
274 | log2mem_write("log2mem starting", __FILE__, __LINE__);
275 |
276 | void* rowptr = log2mem_get_row(__FILE__,__LINE__);
277 | log2mem_append_int(rowptr, 100);
278 | log2mem_append_int(rowptr, 200);
279 | log2mem_append_int(rowptr, 300);
280 |
281 | printf("using some counters\n");
282 | log2mem_counter_label(0, "loops_made");
283 | log2mem_counter_label(1, "misc");
284 |
285 | log2mem_counter_incr(1);
286 | log2mem_counter_incr(1);
287 | log2mem_counter_incr(1);
288 | log2mem_counter_incr(1);
289 |
290 | printf("spawning separate threads, each will log\n");
291 | pthread_attr_t threadAttr;
292 | pthread_attr_init(&threadAttr);
293 |
294 | pthread_t threadA;
295 | pthread_create(&threadA, &threadAttr, THREAD_A_main, 0);
296 |
297 | pthread_t threadB;
298 | pthread_create(&threadB, &threadAttr, THREAD_B_main, 0);
299 |
300 | pthread_t threadC;
301 | pthread_create(&threadC, &threadAttr, THREAD_C_main, 0);
302 |
303 | pthread_t threadD;
304 | pthread_create(&threadD, &threadAttr, THREAD_D_main, 0);
305 |
306 |
307 | printf("waiting for threads to complete ... ");
308 | pthread_join(threadA, 0);
309 | pthread_join(threadB, 0);
310 | pthread_join(threadC, 0);
311 | pthread_join(threadD, 0);
312 | printf("ok\n");
313 |
314 |
315 | int stopflag_variable_id = 1;
316 | const char* stopflag_variable_name = "stopflag";
317 | printf("creating a log2mem variable, id=%d ...\n", stopflag_variable_id);
318 |
319 | log2mem_var_int_init(stopflag_variable_id, 0, stopflag_variable_name);
320 |
321 | printf("waiting until variable, id=%d, is set to 1\n",
322 | stopflag_variable_id);
323 |
324 | printf("==> to trigger loop exit, use the log2mem-util, eg:\n");
325 | printf("\n\t./log2mem-util %s --int[%d]=1\n",log2mem_filename(),stopflag_variable_id);
326 |
327 |
328 |
329 | int j = 0;
330 | void * rptr;
331 | for (j =0 ; j < 1000; j++)
332 | {
333 | // MEMLOGWRITE("function entered"); // 450 nanosec
334 |
335 | // 130 nanosec on 2.5 GHz Core i5 2.50GHz
336 |
337 |
338 | rptr = log2mem_get_row(__FILE__, __LINE__);
339 | log2mem_append_str(rptr, "function is:");
340 | log2mem_append_double(rptr, j*17.0);
341 | log2mem_append_long(rptr, j*17);
342 | }
343 |
344 | while (1)
345 | {
346 | sleep(1);
347 |
348 | /* read a value from the memmap -- this allows the user to interact with the
349 | * program from outside. */
350 | int stopflag = log2mem_var_int_get(stopflag_variable_id);
351 | if (stopflag)
352 | {
353 | printf("detected stopflag==1\n");
354 | break;
355 | }
356 |
357 | }
358 |
359 | rowptr = log2mem_get_row(__FILE__,__LINE__);
360 | log2mem_append_str(rowptr, "application ending");
361 | log2mem_append_str(rowptr, "normally");
362 |
363 | return 0;
364 | }
365 |
--------------------------------------------------------------------------------
/liblog2mem/Makefile.am:
--------------------------------------------------------------------------------
1 | ## Makefile.am -- Process this file with automake to produce Makefile.in
2 | ##
3 | ## This program is free software; you can redistribute it and/or modify
4 | ## it under the terms of the GNU General Public License as published by
5 | ## the Free Software Foundation; either version 2, or (at your option)
6 | ## any later version.
7 | ##
8 | ## This program is distributed in the hope that it will be useful,
9 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | ## GNU General Public License for more details.
12 | ##
13 | ## You should have received a copy of the GNU General Public License
14 | ## along with this program; if not, write to the Free Software
15 | ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 |
17 | # NOTE: AM_CPPFLAGS is ignored in preference to a per-executable (or
18 | # per-library) _CPPFLAGS variable if it is defined
19 | #
20 | # NOTE: it is not good practice to add "-Wall" and "-03" etc here. Those
21 | # choices should be made by the user when they invoke the configure script.
22 | #AM_CFLAGS = -Wall -g3 -ggdb -O0
23 |
24 |
25 | AM_LFLAGS=-pthread
26 |
27 | # Primary defination of our shared library to be created. Notice the
28 | # _LTLIBRARIES key: automake is looking specifically for this pattern and then
29 | # generating make rules which will invoke libtool.
30 | #
31 | # The "lib_" prefix indicates that the named products are to be installed in
32 | # the $(libdir) directory. If we want to build a library that does not get
33 | # installed, then we should use the prefix "noinst_".
34 | lib_LTLIBRARIES = liblog2mem.la
35 |
36 | # The "include_" prefix includes a list of headers to be installed. The
37 | # "nobase_" additional prefix means the directory names are copied too.
38 | nobase_include_HEADERS = log2mem/log2mem.h
39 |
40 | # List the sources for an individual library
41 | liblog2mem_la_SOURCES = log2mem.c
42 |
43 | # Include compile and link flags for an individual library.
44 | #
45 | # Note that to link against a static library which is part of this project, we
46 | # should refers to them with relative paths inside the build directory, for
47 | # example, "../common/libcommon.la"
48 | #
49 | # Note also, because we are using libtool, we should only refer to other
50 | # libtool libraries (*.la)
51 | #
52 | # : extras libtool objects to add to library
53 | #
54 | #libexio_la_CPPFLAGS =
55 | #libexio_la_LIBADD = ../libcpp11/libcpp11.la
56 |
57 | # Note: version info for shared libraries is three number system, where the
58 | # numbers represent: CURRENT : REVISION : AGE
59 | #
60 | # - CURRENT: library version. Only change if API has changed.
61 | # - REVISION: revision of current version. Incr. base on internal changes.
62 | # - AGE: indicates compatibilty with previous version of the shlib.
63 | #
64 | liblog2mem_la_LDFLAGS = -version-info 1:1:0
--------------------------------------------------------------------------------
/liblog2mem/log2mem.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013, Darren Smith
3 |
4 | This file is part of log2mem, a library for providing high performance
5 | logging, timing and debugging to applications.
6 |
7 | log2mem is free software: you can redistribute it and/or modify it under the
8 | terms of the GNU General Public License as published by the Free Software
9 | Foundation, either version 3 of the License, or (at your option) any later
10 | version.
11 |
12 | log2mem is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with log2mem. If not, see .
19 | */
20 |
21 | #include "log2mem/log2mem_dev.h"
22 |
23 | #include "log2mem_atomic.h"
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 |
42 |
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include /* for getopt_long; standard getopt is in unistd.h */
52 | #include
53 | #include
54 | #include /* superset of previous */
55 | #include
56 |
57 |
58 |
59 |
60 | /* */
61 | static struct log2mem_handle * g_log2mem = 0;
62 |
63 | /* */
64 | static int g_log2mem_errno = 0;
65 |
66 | /* */
67 | static volatile int g_log2mem_lock = 0;
68 |
69 |
70 | static volatile int g_log2mem_dummytotal = 0;
71 |
72 | /* These rdtsc implementations are based on code in ACE 6.1.0. The "memory"
73 | * clobber is probably present as an attempt to serialise the rdtsc. */
74 | #if defined(__i386__)
75 | static inline uint64_t read_rdtsc(void)
76 | {
77 | uint64_t edxeax;
78 | asm volatile ("rdtsc" : "=A" (edxeax) : : "memory");
79 | return edxeax;
80 | }
81 | #elif defined (__amd64__) || defined(__x86_64__)
82 | static inline uint64_t read_rdtsc(void)
83 | {
84 | uint32_t edx, eax;
85 | asm volatile ("rdtsc" : "=a"(eax), "=d"(edx) : : "memory");
86 | return ( (uint64_t)eax) |( ((uint64_t)edx)<<32 );
87 | }
88 | #endif
89 |
90 |
91 | // forwards
92 | static char* __default_filename();
93 | static void __default_log2mem_init();
94 |
95 |
96 | #define MEMLOG_PREPARE_PTR { \
97 | if (g_log2mem == 0) \
98 | { \
99 | __default_log2mem_init(); \
100 | } \
101 | }
102 |
103 |
104 | #define MEMLOG_PUT_HDR(PTR, DATATYPE, DATALEN) do { \
105 | struct log2mem_data_hdr* __hdr = (struct log2mem_data_hdr*)(PTR); \
106 | __hdr->type = DATATYPE; \
107 | __hdr->len = sizeof(struct log2mem_data_hdr)+DATALEN; \
108 | PTR += sizeof(struct log2mem_data_hdr); \
109 | } while (0);
110 |
111 | /*
112 | Round up v so to the smallest number n = 2^m which is >= v
113 |
114 | Eg.
115 |
116 | 0 --> 0
117 | 1 --> 1
118 | 2 --> 2
119 | 3 --> 4
120 | 4 --> 4
121 | 5 --> 8
122 |
123 | http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
124 |
125 | */
126 |
127 | inline unsigned int round_up_next_power_of_2_uint(unsigned int v)
128 | {
129 | v--;
130 | v |= v >> 1;
131 | v |= v >> 2;
132 | v |= v >> 4;
133 | v |= v >> 8;
134 | v |= v >> 16;
135 | v++;
136 |
137 | return v;
138 | }
139 |
140 | static
141 | int __log2mem_valid()
142 | {
143 | return (g_log2mem != 0);
144 | }
145 |
146 | static
147 | void __log2mem_error(int errcode, const char* errmsg)
148 | {
149 | g_log2mem_errno = errcode;
150 | // TODO
151 | }
152 |
153 | #define MEMLOG_ERROR_OK 0
154 | #define MEMLOG_ERROR_INCOMPATIBLE_ARCH 1
155 |
156 | const char* log2mem_strerr()
157 | {
158 | switch(g_log2mem_errno)
159 | {
160 | case MEMLOG_ERROR_OK:return "no error";
161 | case MEMLOG_ERROR_INCOMPATIBLE_ARCH:
162 | return "memmap 32/64 bits architecture differs to program";
163 | default: return "unknown error";
164 | };
165 | }
166 |
167 | //----------------------------------------------------------------------
168 |
169 | void log2mem_calculate_layout(const struct log2mem_config * cfg,
170 | struct log2mem_layout * layout)
171 | {
172 | layout->counters_off = MEMLOG_MM_HEADER_SIZE;
173 |
174 | /* place at 8 byte boundary */
175 | layout->rows_off = layout->counters_off +
176 | ((cfg->num_counters * sizeof(struct log2mem_counter) + 8 -1) & ~(8-1));
177 |
178 | /* place at 8 byte boundary */
179 | layout->counter_labels_off = layout->rows_off +
180 | ((cfg->num_rows * calc_row_total_size(cfg) + 8-1) & ~(8-1));
181 |
182 | layout->double_vars_off = layout->counter_labels_off +
183 | ((cfg->num_counters * sizeof(struct log2mem_label) + 8 -1) & ~(8-1));
184 |
185 | layout->int_vars_off = layout->double_vars_off +
186 | ((cfg->num_vars * sizeof(struct log2mem_var_double) + 8 -1) & ~(8-1));
187 |
188 | /* determine size based on the highest offset */
189 | layout->size = layout->int_vars_off +
190 | cfg->num_vars * sizeof(struct log2mem_var_int);
191 |
192 |
193 | /* we want the full memmap size to be a multiple of the system page size */
194 | const int ps = getpagesize();
195 | layout->size = (layout->size + ps - 1) & ~(ps - 1);
196 | }
197 |
198 |
199 | //----------------------------------------------------------------------
200 | static
201 | void __log2mem_calculate_section_pointers(void * mem,
202 | struct log2mem_handle * handle)
203 | {
204 | struct log2mem_mm_header * mmhdr = mem;
205 |
206 | struct log2mem_layout layout;
207 | log2mem_calculate_layout(&(mmhdr->config), &layout);
208 |
209 | memset((void*)handle, 0, sizeof(struct log2mem_handle)); // TODO: pass handle size in
210 | handle->mem = mem;
211 | handle->header = mem;
212 | handle->counters = mem+layout.counters_off;
213 | handle->rows = mem+layout.rows_off;
214 | handle->counter_labels = mem+layout.counter_labels_off;
215 | handle->double_vars = mem+layout.double_vars_off;
216 | handle->int_vars = mem+layout.int_vars_off;
217 | }
218 |
219 | //----------------------------------------------------------------------
220 |
221 | /* Attach to an already existing memmap */
222 | struct log2mem_handle * log2mem_attach (const char* filename)
223 | {
224 | /* to access memmap, both the filehandle and mmap permissions must be set
225 | * appropriately */
226 |
227 | int readonly = 0;
228 | int fdperms = (readonly)? O_RDONLY : O_RDWR;
229 | int mmperms = (readonly)? PROT_READ : PROT_READ | PROT_WRITE;
230 |
231 | /* Open the file. Note: we do not care about the current contents of the
232 | * file, hence we provide the TRUNC flag. */
233 | int fd = open(filename, fdperms);
234 |
235 | struct stat filestat;
236 | if (fstat( fd, &filestat) < 0)
237 | {
238 | // TODO: handle err
239 | return 0;
240 | }
241 |
242 | /* mmap - map the file into memory */
243 | void * addr = mmap(0, filestat.st_size, mmperms, MAP_SHARED, fd, 0);
244 |
245 | if( MAP_FAILED == addr)
246 | {
247 | int __errno = errno;
248 | printf("mmap failed, error %i\n", __errno);
249 | return 0;
250 |
251 | // TODO: cleanup();
252 | }
253 |
254 | // read from memory
255 | size_t i;
256 | const char* chptr = (char*) addr;
257 | for (i=0; i < filestat.st_size; i++, chptr++)
258 | g_log2mem_dummytotal += *chptr;
259 |
260 |
261 | /* set up our pointers the the mm sections */
262 |
263 | g_log2mem = malloc(sizeof(struct log2mem_handle));
264 | __log2mem_calculate_section_pointers(addr, g_log2mem);
265 |
266 | if (!g_log2mem) return 0;
267 |
268 | /* check map architecture */
269 | int myarch = (sizeof(long) * 8);
270 | if (myarch != g_log2mem->header->arch)
271 | {
272 | __log2mem_error(MEMLOG_ERROR_INCOMPATIBLE_ARCH, "incompatible architecture");
273 | g_log2mem = NULL;
274 | return g_log2mem;
275 | }
276 |
277 | // TODO: perform a size check .. ie, the size of the memmap should match
278 | // thelayout
279 |
280 | return g_log2mem;
281 | }
282 |
283 | //----------------------------------------------------------------------
284 |
285 | /*
286 | Create and configure an instance of log2mem_handle, backing it with a
287 | memory-mapped file.
288 | */
289 |
290 | static
291 | struct log2mem_handle * __log2mem_create(const char* fn,
292 | struct log2mem_config config)
293 | {
294 | struct log2mem_handle * ptr = NULL;
295 |
296 | ptr = malloc(sizeof(struct log2mem_handle));
297 | memset((void*)ptr, 0, sizeof(struct log2mem_handle));
298 |
299 | /* copy or create a filename */
300 | if (fn)
301 | ptr->filename = strdup(fn);
302 | else
303 | ptr->filename = __default_filename();
304 |
305 | // round up to power-of-2
306 | config.num_counters = round_up_next_power_of_2_uint(config.num_counters);
307 | config.num_counters += (config.num_counters == 0);
308 | config.num_rows = round_up_next_power_of_2_uint(config.num_rows);
309 | config.num_rows += (config.num_rows == 0);
310 | config.num_vars = round_up_next_power_of_2_uint(config.num_vars);
311 |
312 | /* determine the memmap layout */
313 | struct log2mem_layout layout;
314 | log2mem_calculate_layout(&config, &layout);
315 |
316 | /* obtain filename */
317 |
318 | /* Open the file. Note: we do not care about the current contents of the
319 | * file, hence we provide the TRUNC flag. */
320 | int fd = open(ptr->filename, O_RDWR | O_CREAT, 0640);
321 |
322 | /* Enlarge the file to the length required for our data, and also that it
323 | * has a size which is a multiple of the system page size */
324 | if (ftruncate(fd, layout.size) != 0)
325 | {
326 | int __errno = errno;
327 | printf("ftruncate failed, error %i\n", __errno);
328 |
329 | // TODO: need a strategy for dealing with log2mem errors
330 | exit(1); // TODO: remove this
331 | /* TODO: check for error */
332 | }
333 |
334 | /* TODO: fstat the file, to check its size */
335 |
336 |
337 | /* mmap - map the file into memory */
338 | ptr->mem = mmap(0, layout.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
339 |
340 | if( MAP_FAILED == ptr->mem)
341 | {
342 | // TODO: need to get system error string here.
343 | int __errno = errno;
344 | printf("mmap failed, error %i\n", __errno);
345 | exit(1); // TODO: remove this
346 | /* __errno = errno; */
347 | /* if (m_logsvc and m_logsvc->want_error()) */
348 | /* { */
349 | /* std::ostringstream os; */
350 | /* os << "Failed to perform initial mmap. errno=" << __errno; */
351 | /* m_logsvc->error( os.str(), true ); */
352 | /* } */
353 | /* cleanup(); */
354 | /* return -1; */
355 | }
356 |
357 | memset(ptr->mem, 0, layout.size);
358 |
359 | /* TODO: there is a function for calculating the pointers based on offsets
360 | ... why is that not being used here? */
361 |
362 | /* set up our pointers the the mm sections */
363 | ptr->header = (struct log2mem_mm_header*) ptr->mem;
364 | ptr->counters = (struct log2mem_counter*) (ptr->mem + layout.counters_off);
365 | ptr->rows = (struct log2mem_row*) (ptr->mem + layout.rows_off);
366 | ptr->counter_labels = (struct log2mem_label*) (ptr->mem + layout.counter_labels_off);
367 | ptr->double_vars = (struct log2mem_var_double*) (ptr->mem + layout.double_vars_off);
368 | ptr->int_vars = (struct log2mem_var_int*) (ptr->mem + layout.int_vars_off);
369 |
370 | /* populate the memmap */
371 |
372 | snprintf(ptr->header->desc, MEMLOG_DESC_LEN,
373 | "log2mem memmap version %d", MEMLOG_VERSION);
374 | ptr->header->desc[MEMLOG_DESC_LEN-1] = '\0';
375 |
376 | ptr->header->version = MEMLOG_VERSION;
377 |
378 | long int endian = 1; char *p = (char *) &endian;
379 |
380 | ptr->header->flags = p[0]? 0x1 : 0;
381 | ptr->header->arch = (sizeof(long) * 8);
382 |
383 | ptr->header->config = config;
384 | ptr->header->nextrow = 0;
385 |
386 | time_t clock = time(0);
387 | struct tm _tm;
388 | localtime_r(&clock, &_tm);
389 | memset(ptr->header->datecreated, 0, MEMLOG_TIMESTR_LEN);
390 | snprintf(ptr->header->datecreated, MEMLOG_TIMESTR_LEN-1,
391 | "%04i/%02d/%02d %02i:%02i:%02i",
392 | _tm.tm_year+1900, _tm.tm_mon+1, _tm.tm_mday,
393 | _tm.tm_hour, _tm.tm_min, _tm.tm_sec);
394 | ptr->header->datecreated[MEMLOG_TIMESTR_LEN-1] = '\0';
395 |
396 | return ptr;
397 | }
398 |
399 | //----------------------------------------------------------------------
400 | void log2mem_init(const char* filename,
401 | const struct log2mem_config* userconfig,
402 | int configsize)
403 | {
404 | /* copy the user config to a local object, so that we can deal with a client
405 | * applicaiton that might be compiled to an older version of the config
406 | * struct.
407 | */
408 | struct log2mem_config config;
409 | memset(&config, 0, sizeof(struct log2mem_config));
410 | memcpy(&config, userconfig, configsize);
411 |
412 | /* double checked locking */
413 | if (g_log2mem == 0)
414 | {
415 | /* TODO: review, does this really need to be a spinlock? I think a
416 | pthread would be okay here? */
417 | log2mem_atomic_spinlock(&g_log2mem_lock);
418 |
419 | if (g_log2mem == 0)
420 | {
421 | g_log2mem = __log2mem_create(filename, config);
422 | }
423 |
424 | log2mem_atomic_spinunlock(&g_log2mem_lock);
425 | }
426 |
427 | }
428 |
429 | //----------------------------------------------------------------------
430 | void log2mem_counter_incr(int counterid)
431 | {
432 | log2mem_counter_add(counterid, 1);
433 | }
434 |
435 | //----------------------------------------------------------------------
436 | void log2mem_counter_add(int counterid, int valueToAdd)
437 | {
438 | MEMLOG_PREPARE_PTR;
439 | if (!__log2mem_valid()) return;
440 |
441 | int idx = counterid & (g_log2mem->header->config.num_counters-1);
442 | struct log2mem_counter* counter = &g_log2mem->counters[idx];
443 | log2mem_atomic_incr_fetch_int( (int*) &(counter->value.v) , valueToAdd);
444 | }
445 |
446 | //----------------------------------------------------------------------
447 | void log2mem_counter_label(int counterid, const char* src)
448 | {
449 | MEMLOG_PREPARE_PTR;
450 | if (!__log2mem_valid()) return;
451 |
452 | int idx = counterid & (g_log2mem->header->config.num_counters-1);
453 | strncpy(g_log2mem->counter_labels[idx].text, src, MEMLOG_LABEL_LEN-1);
454 | g_log2mem->counters[idx].used = 1;
455 | }
456 |
457 | //----------------------------------------------------------------------
458 |
459 | /*
460 | * NOTE: this push function must not be used for pushing c-string.
461 | */
462 | static inline
463 | int __log2mem_push(struct log2mem_row* row,
464 | int datatype,
465 | int datalen,
466 | const void* data)
467 | {
468 | /* g_log2mem should already be initialised by now */
469 | const int remain = g_log2mem->header->config.row_len - row->datalen;
470 | const int totlen = sizeof(struct log2mem_data_hdr) + datalen;
471 |
472 | if (totlen <= remain)
473 | {
474 | char* ptr = (char*) log2mem_row_payload(row) + row->datalen;
475 | MEMLOG_PUT_HDR(ptr, datatype, datalen);
476 |
477 | memcpy(ptr, data, datalen);
478 |
479 | row->datalen += totlen;
480 | }
481 | }
482 |
483 | static inline
484 | int __log2mem_push_str(struct log2mem_row* row,
485 | int datatype,
486 | int len,
487 | const void* str)
488 | {
489 | /* g_log2mem should already be initialised by now */
490 | const int remain = g_log2mem->header->config.row_len - row->datalen;
491 | const int totlen = sizeof(struct log2mem_data_hdr) + (len+1);
492 |
493 | if (totlen <= remain)
494 | {
495 | char* ptr = (char*) log2mem_row_payload(row) + row->datalen;
496 | MEMLOG_PUT_HDR(ptr, datatype, (len+1));
497 |
498 | memcpy(ptr, str, len);
499 | ptr+=len;
500 | *ptr='\0'; ptr++; /* push a null char */
501 |
502 | row->datalen += totlen;
503 | }
504 | }
505 | //----------------------------------------------------------------------
506 | log2mem_ts log2mem_time()
507 | {
508 | MEMLOG_PREPARE_PTR;
509 | if (__log2mem_valid())
510 | {
511 | /* get time */
512 | switch(g_log2mem->header->config.options & MEMLOG_CLOCKSOURCE_MASK)
513 | {
514 | case MEMLOG_RDTSC : {
515 | return read_rdtsc();
516 | break;
517 | }
518 | case MEMLOG_GETTIMEOFDAY : {
519 | struct timeval tp;
520 | gettimeofday(&tp, 0);
521 | // normalise to nanosec
522 | return (tp.tv_sec << MEMLOG_BITS_NANO) + (tp.tv_usec*1000);
523 | break;
524 | };
525 | case MEMLOG_CLOCKGETTIME : {
526 | struct timespec ts;
527 | clock_gettime(CLOCK_REALTIME, &ts);
528 | return (ts.tv_sec << MEMLOG_BITS_NANO) + ts.tv_nsec;
529 | break;
530 | };
531 | default: return 0;
532 | }
533 | }
534 | }
535 | //----------------------------------------------------------------------
536 | static
537 | struct log2mem_row * __log2mem_init_row(const char* filename, int lineno)
538 | {
539 | MEMLOG_PREPARE_PTR;
540 | if (__log2mem_valid())
541 | {
542 | /* obtain a row id */
543 | unsigned int rowid = log2mem_atomic_incr_fetch_uint(
544 | (unsigned int*) &g_log2mem->header->nextrow,1)-1;
545 |
546 | const int rowidx = rowid & (g_log2mem->header->config.num_rows-1);
547 |
548 | /* obtain a row pointer */
549 | const int row_total_size = calc_row_total_size(&g_log2mem->header->config);
550 | struct log2mem_row * r = (struct log2mem_row *) ((char*)g_log2mem->rows
551 | + (rowidx * row_total_size));
552 |
553 | if (g_log2mem->header->config.options & MEMLOG_THREADID)
554 | r->tid = syscall(SYS_gettid);
555 |
556 | /* get time */
557 | switch(g_log2mem->header->config.options & MEMLOG_CLOCKSOURCE_MASK)
558 | {
559 | case MEMLOG_RDTSC : {
560 | r->ts = read_rdtsc();
561 | break;
562 | }
563 | case MEMLOG_GETTIMEOFDAY : {
564 | struct timeval tp;
565 | gettimeofday(&tp, 0);
566 | // normalise to nanosec
567 | r->ts = (tp.tv_sec << MEMLOG_BITS_NANO) + (tp.tv_usec*1000);
568 | break;
569 | };
570 | case MEMLOG_CLOCKGETTIME : {
571 | struct timespec ts;
572 | clock_gettime(CLOCK_REALTIME, &ts);
573 | r->ts = (ts.tv_sec << MEMLOG_BITS_NANO) + ts.tv_nsec;
574 | break;
575 | };
576 | }
577 |
578 | r->id = rowid;
579 | r->datalen = 0;
580 |
581 | if ((g_log2mem->header->config.options & MEMLOG_FILELINE) && filename)
582 | {
583 | __log2mem_push_str(r, MEMLOG_DATATYPE_FILENAME, strlen(filename), filename);
584 | __log2mem_push(r, MEMLOG_DATATYPE_LINENO, sizeof(lineno), &lineno);
585 | }
586 |
587 | return r;
588 | }
589 | else
590 | {
591 | return 0;
592 | }
593 |
594 | }
595 |
596 | //----------------------------------------------------------------------
597 | void* log2mem_write(const char* str, const char* filename, int lineno)
598 | {
599 | struct log2mem_row * r = __log2mem_init_row(filename, lineno);
600 | if (r && str)
601 | {
602 | __log2mem_push_str(r, MEMLOG_DATATYPE_STRING, strlen(str), str);
603 | }
604 |
605 | return r;
606 | }
607 |
608 | //----------------------------------------------------------------------
609 | void* log2mem_get_row(const char* filename, int lineno)
610 | {
611 | return __log2mem_init_row(filename, lineno);
612 | }
613 | //----------------------------------------------------------------------
614 | void log2mem_append_uint(void* r, unsigned int d)
615 | {
616 | if (r)
617 | {
618 | __log2mem_push(r, MEMLOG_DATATYPE_UINT, sizeof(d), &d);
619 | }
620 | }
621 |
622 | //----------------------------------------------------------------------
623 | void log2mem_append_int(void* r, int d)
624 | {
625 | if (r)
626 | {
627 | __log2mem_push(r, MEMLOG_DATATYPE_INT, sizeof(d), &d);
628 | }
629 | }
630 |
631 | //----------------------------------------------------------------------
632 | void log2mem_append_str2(void* r, const char* str, int len)
633 | {
634 | if (r && str)
635 | {
636 | __log2mem_push_str(r, MEMLOG_DATATYPE_STRING, len, str);
637 | }
638 | }
639 |
640 | //----------------------------------------------------------------------
641 | void log2mem_append_str(void* r, const char* str)
642 | {
643 | if (r && str)
644 | {
645 | __log2mem_push_str(r, MEMLOG_DATATYPE_STRING, strlen(str), str);
646 | }
647 | }
648 |
649 | //----------------------------------------------------------------------
650 | void log2mem_append_ulong(void* r, unsigned long d)
651 | {
652 | if (r)
653 | {
654 | __log2mem_push(r, MEMLOG_DATATYPE_ULONG, sizeof(d), &d);
655 | }
656 | }
657 |
658 | //----------------------------------------------------------------------
659 | void log2mem_append_long(void* r, long d)
660 | {
661 | if (r)
662 | {
663 | __log2mem_push(r, MEMLOG_DATATYPE_LONG, sizeof(d), &d);
664 | }
665 | }
666 | //----------------------------------------------------------------------
667 | void log2mem_append_float(void* r, float d)
668 | {
669 | if (r)
670 | {
671 | __log2mem_push(r, MEMLOG_DATATYPE_FLOAT, sizeof(d), &d);
672 | }
673 | }
674 |
675 | //----------------------------------------------------------------------
676 | void log2mem_append_double(void* r, double d)
677 | {
678 | if (r)
679 | {
680 | __log2mem_push(r, MEMLOG_DATATYPE_DOUBLE, sizeof(d), &d);
681 | }
682 | }
683 |
684 | //----------------------------------------------------------------------
685 | void log2mem_append_char(void* r, char d)
686 | {
687 | if (r)
688 | {
689 | __log2mem_push(r, MEMLOG_DATATYPE_CHAR, sizeof(d), &d);
690 | }
691 | }
692 |
693 | //----------------------------------------------------------------------
694 | void* log2mem_time_event4(int flowid, int msgref, const char* str, int len)
695 | {
696 | struct log2mem_row * row = __log2mem_init_row(0, 0);
697 |
698 | if (row)
699 | {
700 | int len_needed = 2*sizeof(struct log2mem_data_hdr)
701 | + 2* sizeof(int);
702 |
703 | if (str && len>0)
704 | len_needed += sizeof(struct log2mem_data_hdr) + (len+1);
705 |
706 | const int avail = g_log2mem->header->config.row_len - row->datalen;
707 |
708 | if (len_needed <= avail)
709 | {
710 | const int row_datalen = 0; /* there is no data already in the row */
711 | char* ptr = (char*) (log2mem_row_payload(row) + row_datalen);
712 | int* intptr;
713 |
714 | // push record
715 | MEMLOG_PUT_HDR(ptr, MEMLOG_DATATYPE_INT, sizeof(flowid));
716 | intptr = (int*) ptr;
717 | *intptr = flowid;
718 | ptr += sizeof(flowid);
719 |
720 | // push record
721 | MEMLOG_PUT_HDR(ptr, MEMLOG_DATATYPE_INT, sizeof(msgref));
722 | intptr = (int*) ptr;
723 | *intptr = msgref;
724 | ptr += sizeof(msgref);
725 |
726 | // push record
727 | if (str && len>0)
728 | {
729 | MEMLOG_PUT_HDR(ptr, MEMLOG_DATATYPE_STRING, (len+1));
730 |
731 | memcpy(ptr, str, len);
732 | ptr+=len;
733 | *ptr='\0'; ptr++; /* push a null char */
734 | }
735 |
736 | row->datalen += len_needed;
737 | }
738 | }
739 |
740 | return row;
741 | }
742 | //----------------------------------------------------------------------
743 |
744 | void* log2mem_time_event2(int flowid, int msgid)
745 | {
746 | return log2mem_time_event4(flowid, msgid, 0, 0);
747 | }
748 | void* log2mem_time_event3(int flowid, int msgid, const char* msgstr)
749 | {
750 | return log2mem_time_event4(flowid, msgid, msgstr, strlen(msgstr));
751 | }
752 |
753 | void* log2mem_set_ts(void* r, log2mem_ts ts)
754 | {
755 | if (r)
756 | {
757 | struct log2mem_row * row = (struct log2mem_row *)r;
758 | row->ts = ts;
759 | }
760 | }
761 |
762 | //----------------------------------------------------------------------
763 | static void __default_log2mem_init()
764 | {
765 | struct log2mem_config cfg;
766 |
767 | memset(&cfg, 0, sizeof(cfg));
768 |
769 | cfg.options = MEMLOG_FILELINE|MEMLOG_THREADID;
770 | cfg.num_counters = 16;
771 | cfg.num_rows = 1<<16;
772 | cfg.row_len = 256;
773 | cfg.num_vars = 10;
774 |
775 | // TODO: also provide a pattern, eg, MEMLOG_FILEPATTERN, support things like
776 | // %P for pid etc., %H etc.
777 |
778 | char * s = getenv("MEMLOG_FILENAME");
779 | log2mem_init(s, &cfg, sizeof(struct log2mem_config));
780 | }
781 |
782 | //----------------------------------------------------------------------
783 |
784 | static char* __build_user_id()
785 | {
786 | size_t buflen = 256;
787 | char* buf = malloc( buflen );
788 | memset(buf, 0, sizeof(buf));
789 |
790 | // try, using getlogin_r
791 | if (getlogin_r(buf, buflen) != 0)
792 | {
793 | buf[0]='\0';
794 | }
795 |
796 | // or, try cuserid
797 | if (buf[0]=='\0')
798 | {
799 | char buf_cuserid[1024*2];
800 | memset(buf_cuserid, 0, sizeof(buf_cuserid));
801 | cuserid(buf);
802 | if (buf_cuserid[0] != '\0')
803 | {
804 | // TODO: u tback in
805 | // memcpy(username, buf_cuserid, std::min(sizeof(username), sizeof(buf_cuserid)));
806 | }
807 | }
808 |
809 | // or, try LOGNAME
810 | if (buf[0]=='\0')
811 | {
812 | char* s = getenv("LOGNAME");
813 | if (s) strncpy(buf, s, buflen);
814 | }
815 |
816 | // or, try USER
817 | if (buf[0]=='\0')
818 | {
819 | char* s = getenv("USER");
820 | if (s) strncpy(buf, s, buflen);
821 | }
822 |
823 | buf[buflen-1] = '\0';
824 |
825 | return buf;
826 | }
827 |
828 |
829 | //----------------------------------------------------------------------
830 | static char* __default_filename()
831 | {
832 | int buflen= 1024*4;
833 | char * buf = malloc(buflen);
834 | memset(buf, 0, buflen);
835 |
836 | char * username = __build_user_id();
837 |
838 | snprintf(buf, buflen, "/var/tmp/log2mem-%s.dat", username);
839 |
840 | free(username);
841 |
842 | return buf;
843 | }
844 |
845 | //----------------------------------------------------------------------
846 | void log2mem_var_double_init(unsigned int id, double value, const char* src)
847 | {
848 | MEMLOG_PREPARE_PTR;
849 | if (!__log2mem_valid()) return;
850 |
851 | int idx = id & (g_log2mem->header->config.num_vars-1);
852 |
853 | if (g_log2mem->double_vars[idx].flags & log2mem_eInitialised) return;
854 |
855 | g_log2mem->double_vars[idx].value = value;
856 | g_log2mem->double_vars[idx].flags |= (log2mem_eUsed | log2mem_eInitialised);
857 |
858 | if (src)
859 | {
860 | strncpy(g_log2mem->double_vars[idx].text, src, MEMLOG_LABEL_LEN-1);
861 | g_log2mem->double_vars[idx].text[MEMLOG_LABEL_LEN-1] = '\0';
862 | }
863 | }
864 |
865 | //----------------------------------------------------------------------
866 |
867 | void log2mem_var_double_set(unsigned int id, double d)
868 | {
869 | MEMLOG_PREPARE_PTR;
870 | if (!__log2mem_valid()) return;
871 |
872 | int idx = id & (g_log2mem->header->config.num_vars-1);
873 | g_log2mem->double_vars[idx].value = d;
874 | g_log2mem->double_vars[idx].flags |= log2mem_eUsed;
875 | }
876 |
877 | //----------------------------------------------------------------------
878 |
879 | double log2mem_var_double_get(unsigned int id)
880 | {
881 | MEMLOG_PREPARE_PTR;
882 | if (!__log2mem_valid()) return 0.0;
883 |
884 | int idx = id & (g_log2mem->header->config.num_vars-1);
885 | return g_log2mem->double_vars[idx].value;
886 | }
887 |
888 | //----------------------------------------------------------------------
889 |
890 | int log2mem_var_double_used(unsigned int id)
891 | {
892 | MEMLOG_PREPARE_PTR;
893 | if (!__log2mem_valid()) return 0;
894 |
895 | int idx = id & (g_log2mem->header->config.num_vars-1);
896 | return g_log2mem->double_vars[idx].flags & log2mem_eUsed;
897 | }
898 |
899 | //----------------------------------------------------------------------
900 |
901 | void log2mem_var_int_init(unsigned int id, int value, const char* src)
902 | {
903 | MEMLOG_PREPARE_PTR;
904 | if (!__log2mem_valid()) return;
905 |
906 | int idx = id & (g_log2mem->header->config.num_vars-1);
907 |
908 | if (g_log2mem->int_vars[idx].flags & log2mem_eInitialised) return;
909 |
910 | g_log2mem->int_vars[idx].value = value;
911 | g_log2mem->int_vars[idx].flags |= (log2mem_eUsed | log2mem_eInitialised);
912 |
913 | if (src)
914 | {
915 | strncpy(g_log2mem->int_vars[idx].text, src, MEMLOG_LABEL_LEN-1);
916 | g_log2mem->int_vars[idx].text[MEMLOG_LABEL_LEN-1] = '\0';
917 | }
918 | }
919 | //----------------------------------------------------------------------
920 |
921 | void log2mem_var_int_set(unsigned int id, int d)
922 | {
923 | MEMLOG_PREPARE_PTR;
924 | if (!__log2mem_valid()) return;
925 |
926 | int idx = id & (g_log2mem->header->config.num_vars-1);
927 | g_log2mem->int_vars[idx].value = d;
928 | g_log2mem->int_vars[idx].flags |= log2mem_eUsed;
929 | }
930 |
931 | //----------------------------------------------------------------------
932 |
933 | int log2mem_var_int_get(unsigned int id)
934 | {
935 | MEMLOG_PREPARE_PTR;
936 | if (!__log2mem_valid()) return 0.0;
937 |
938 | int idx = id & (g_log2mem->header->config.num_vars-1);
939 | return g_log2mem->int_vars[idx].value;
940 | }
941 |
942 | //----------------------------------------------------------------------
943 |
944 | int log2mem_var_int_used(unsigned int id)
945 | {
946 | MEMLOG_PREPARE_PTR;
947 | if (!__log2mem_valid()) return 0;
948 |
949 | int idx = id & (g_log2mem->header->config.num_vars-1);
950 | return g_log2mem->int_vars[idx].flags & log2mem_eUsed;
951 | }
952 |
953 |
954 | //----------------------------------------------------------------------
955 |
956 | int log2mem_valid()
957 | {
958 | MEMLOG_PREPARE_PTR;
959 | if (__log2mem_valid())
960 | return 1;
961 | else
962 | return 0;
963 | }
964 |
965 |
966 | //----------------------------------------------------------------------
967 |
968 | const char* log2mem_filename()
969 | {
970 | MEMLOG_PREPARE_PTR;
971 | if (__log2mem_valid())
972 | {
973 | return g_log2mem->filename;
974 | }
975 | else
976 | return 0;
977 | }
978 |
979 |
980 | //----------------------------------------------------------------------
981 |
982 |
983 |
984 | void log2mem_ts_to_timespec(log2mem_ts ts, struct timespec* tspec)
985 | {
986 | // used for CLOCKGETTIME
987 | tspec->tv_sec = (ts >> MEMLOG_BITS_NANO) & MEMLOG_MASK_SECS;
988 | tspec->tv_nsec = (ts & MEMLOG_MASK_NANO);
989 | }
990 |
991 | //----------------------------------------------------------------------
992 |
993 | void log2mem_ts_to_timeval(log2mem_ts ts,struct timeval* tval)
994 | {
995 | // used for GETTIMEOFDAY
996 | tval->tv_sec = (ts >> MEMLOG_BITS_NANO) & MEMLOG_MASK_SECS;
997 | tval->tv_usec = (ts & MEMLOG_MASK_NANO) / 1000;
998 | }
999 |
1000 | //----------------------------------------------------------------------
1001 |
--------------------------------------------------------------------------------
/liblog2mem/log2mem/log2mem.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013, Darren Smith
3 |
4 | This file is part of log2mem, a library for providing high performance
5 | logging, timing and debugging to applications.
6 |
7 | log2mem is free software: you can redistribute it and/or modify it under the
8 | terms of the GNU General Public License as published by the Free Software
9 | Foundation, either version 3 of the License, or (at your option) any later
10 | version.
11 |
12 | log2mem is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with log2mem. If not, see .
19 | */
20 |
21 | #include
22 |
23 | #ifndef _MEMLOG_H_
24 | #define _MEMLOG_H_
25 |
26 | #define MEMLOGFL __FILE__,__LINE__
27 | #define MEMLOGWRITE( X ) log2mem_write( X, __FILE__, __LINE__)
28 |
29 | #ifdef __cplusplus
30 | extern "C" {
31 | #endif
32 |
33 |
34 | #define MEMLOG_CLOCKSOURCE_MASK 0x0C /* bits 2 and 3 */
35 |
36 | enum log2mem_options
37 | {
38 | MEMLOG_FILELINE = 1,
39 | MEMLOG_THREADID = (1 << 1),
40 |
41 | /* CLOCK SOURCE */
42 | MEMLOG_GETTIMEOFDAY = (1 << 2), /* microseconds */
43 | MEMLOG_CLOCKGETTIME = (1 << 3), /* nanoseconds */
44 | MEMLOG_RDTSC = ((1<<2) + (1<<3)) /* raw cpu */
45 |
46 | };
47 |
48 | struct log2mem_config
49 | {
50 | int options;
51 | unsigned int num_counters;
52 | unsigned int num_rows;
53 | unsigned int row_len;
54 | unsigned int num_vars;
55 | };
56 |
57 | /* timestamp format used by log2mem */
58 | typedef uint64_t log2mem_ts;
59 |
60 |
61 | /* Initialisation
62 | */
63 | /*
64 |
65 | - Ideally, this should be called before the first log2mem statement is invoked,
66 | since the first call can take additional time to complete.
67 |
68 | */
69 | void log2mem_init(const char* filename,
70 | const struct log2mem_config * config,
71 | int config_struct_len);
72 |
73 | /* If log2mem has failed, get the last error */
74 | const char* log2mem_strerr();
75 |
76 | /* Check if log2mem is valid */
77 | int log2mem_valid();
78 |
79 | /* Return the filename of the memmap file, or null if log2mem is not ready */
80 | const char* log2mem_filename();
81 |
82 | /* Logging
83 | *
84 | */
85 |
86 | /* Log a string */
87 | void* log2mem_write(const char* msg, const char* filename, int lineno);
88 |
89 | /* Obtain a logging row, to later append values */
90 | void* log2mem_get_row(const char* filename, int lineno);
91 |
92 | /* Append data to previously obtained logging row */
93 | void log2mem_append_str(void* rowptr, const char* str);
94 | void log2mem_append_str2(void* rowptr, const char* str, int len);
95 | void log2mem_append_int(void* rowptr, int);
96 | void log2mem_append_uint(void* rowptr, unsigned int);
97 | void log2mem_append_long(void* rowptr, long);
98 | void log2mem_append_ulong(void* rowptr, unsigned long);
99 | void log2mem_append_float(void* rowptr, float);
100 | void log2mem_append_double(void* rowptr,double);
101 | void log2mem_append_char(void* rowptr, char);
102 |
103 | /* Utility functions for putting timing records into a row */
104 | void* log2mem_time_event4(int flowid, int id, const char* msg, int msglen);
105 | void* log2mem_time_event2(int flowid, int id);
106 | void* log2mem_time_event3(int flowid, int id, const char* msg);
107 |
108 | log2mem_ts log2mem_time(); // TODO: can we make this inline?
109 |
110 | void* log2mem_set_ts(void* rowptr, log2mem_ts ts); // TOO clumsy ... what this as a first class function
111 |
112 | /* Counters */
113 | void log2mem_counter_incr(int counterid);
114 | void log2mem_counter_add(int counterid, int value);
115 | void log2mem_counter_label(int counterid, const char* label);
116 |
117 | /* Variables */
118 |
119 | void log2mem_var_double_init(unsigned int id, double, const char*);
120 | int log2mem_var_double_used(unsigned int id);
121 | void log2mem_var_double_set(unsigned int id, double);
122 | double log2mem_var_double_get(unsigned int id);
123 |
124 | void log2mem_var_int_init(unsigned int id, int, const char*);
125 | int log2mem_var_int_used(unsigned int id);
126 | void log2mem_var_int_set(unsigned int id, int);
127 | int log2mem_var_int_get(unsigned int id);
128 |
129 | #ifdef __cplusplus
130 | }
131 | #endif
132 |
133 | #endif
134 |
--------------------------------------------------------------------------------
/liblog2mem/log2mem/log2mem_dev.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013, Darren Smith
3 |
4 | This file is part of log2mem, a library for providing high performance
5 | logging, timing and debugging to applications.
6 |
7 | log2mem is free software: you can redistribute it and/or modify it under the
8 | terms of the GNU General Public License as published by the Free Software
9 | Foundation, either version 3 of the License, or (at your option) any later
10 | version.
11 |
12 | log2mem is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with log2mem. If not, see .
19 | */
20 |
21 | #ifndef _MEMLOG_DEV_H_
22 | #define _MEMLOG_DEV_H_
23 |
24 | #include "log2mem/log2mem.h"
25 |
26 | #include
27 |
28 |
29 | #ifdef __cplusplus
30 | extern "C" {
31 | #endif
32 |
33 | #define MEMLOG_VERSION 2
34 |
35 | #define MEMLOG_LABEL_LEN 64
36 |
37 | #define MEMLOG_DESC_LEN 24
38 | #define MEMLOG_TIMESTR_LEN 32
39 |
40 | /* Memmap header size -- always fixed to this */
41 | #define MEMLOG_MM_HEADER_SIZE 256
42 |
43 | /* Data types stored with rows are represented via datatype ID */
44 | #define MEMLOG_DATATYPE_FILENAME 1
45 | #define MEMLOG_DATATYPE_STRING 2
46 | #define MEMLOG_DATATYPE_UINT 3
47 | #define MEMLOG_DATATYPE_INT 4
48 | #define MEMLOG_DATATYPE_ULONG 5
49 | #define MEMLOG_DATATYPE_LONG 6
50 | #define MEMLOG_DATATYPE_FLOAT 7
51 | #define MEMLOG_DATATYPE_DOUBLE 8
52 | #define MEMLOG_DATATYPE_CHAR 9
53 | #define MEMLOG_DATATYPE_LINENO 10 /* lineno is an integer */
54 |
55 | /*
56 |
57 | for time values, the 64 bits are split into:
58 |
59 | | seconds | nanosec |
60 | |<--- 34 --->|<--- 30 --->|
61 |
62 | 34 bit mask: 0x3FFFFFFFF
63 | 30 bit mask: 0x3FFFFFFF
64 |
65 | */
66 |
67 | #define MEMLOG_BITS_SECS 34
68 | #define MEMLOG_MASK_SECS 0x3FFFFFFFF
69 |
70 | #define MEMLOG_BITS_NANO 30
71 | #define MEMLOG_MASK_NANO 0x3FFFFFFF
72 |
73 | /* Memmap header */
74 | struct log2mem_mm_header
75 | {
76 | char desc[MEMLOG_DESC_LEN];
77 | int flags;
78 | unsigned int nextrow;
79 | struct log2mem_config config;
80 | int version;
81 | int arch;
82 | char datecreated[MEMLOG_TIMESTR_LEN];
83 | };
84 |
85 |
86 | /* Data item header */
87 | struct log2mem_data_hdr
88 | {
89 | char type;
90 | unsigned int len; // length of payload + length of this header
91 | };
92 |
93 |
94 | struct log2mem_row
95 | {
96 | int tid;
97 | log2mem_ts ts;
98 | unsigned int id;
99 | unsigned int datalen;
100 | };
101 |
102 | /*
103 | Place our atomic int within a simple struct wrapper, to prevent variables of
104 | type atomic_int from being accidentally placed within standard numeric
105 | expressions (which would invalidate atomicity). Eg, atomic_int i; i = i + 1;
106 | causes a compiler error.
107 | */
108 | struct atomic_int
109 | {
110 | volatile int v;
111 | };
112 |
113 | struct log2mem_counter
114 | {
115 | struct atomic_int value;
116 | int used;
117 | };
118 |
119 | /* calculate the payload address for a row address */
120 | static inline char* log2mem_row_payload(struct log2mem_row * r)
121 | {
122 | char* p = (char*) r;
123 | return p + sizeof(struct log2mem_row);
124 | }
125 |
126 | static inline size_t calc_row_total_size(const struct log2mem_config * cfg)
127 | {
128 | return sizeof(struct log2mem_row) + cfg->row_len;
129 | }
130 |
131 | enum log2mem_bitflags
132 | {
133 | log2mem_eInitialised = 0x01,
134 | log2mem_eUsed = 0x02
135 | };
136 |
137 | struct log2mem_label
138 | {
139 | char text[ MEMLOG_LABEL_LEN ];
140 | };
141 |
142 | struct log2mem_var_double
143 | {
144 | double value;
145 | int flags;
146 | char text[ MEMLOG_LABEL_LEN ];
147 | // TODO: need to add some kind of lock, spinlock?
148 | };
149 |
150 | struct log2mem_var_int
151 | {
152 | int value;
153 | int flags;
154 | char text[ MEMLOG_LABEL_LEN ];
155 | // TODO: need to add some kind of lock, spinlock?
156 | };
157 |
158 | struct log2mem_handle
159 | {
160 | void * mem;
161 |
162 | /* pointers to major memmap sections */
163 | struct log2mem_mm_header * header;
164 | struct log2mem_counter * counters;
165 | struct log2mem_row * rows;
166 | struct log2mem_label * counter_labels;
167 | struct log2mem_var_double* double_vars;
168 | struct log2mem_var_int* int_vars;
169 |
170 | char* filename;
171 | };
172 |
173 | /* Attach to an existing memmap file, and return handle. Returns NULL upon
174 | * failure. */
175 | struct log2mem_handle *
176 | log2mem_attach (const char* filename);
177 |
178 | /* Memmap layout is described by the offsets to the major sections */
179 | struct log2mem_layout
180 | {
181 | int size; /* whole region footprint */
182 |
183 | /* int header_off; -- not needed, because always zero */
184 |
185 | int counters_off;
186 | int rows_off;
187 | int counter_labels_off;
188 | int double_vars_off;
189 | int int_vars_off;
190 | };
191 |
192 | void log2mem_calculate_layout(const struct log2mem_config * cfg,
193 | struct log2mem_layout * layout);
194 |
195 | /*
196 | struct timeval {
197 | time_t tv_sec;
198 | suseconds_t tv_usec;
199 | };
200 |
201 | struct timespec {
202 | time_t tv_sec;
203 | long tv_nsec;
204 | };
205 | */
206 |
207 | struct timespec;
208 | struct timeval;
209 |
210 | void log2mem_ts_to_timespec(log2mem_ts, struct timespec*);
211 | void log2mem_ts_to_timeval(log2mem_ts,struct timeval*);
212 |
213 | #ifdef __cplusplus
214 | }
215 | #endif
216 |
217 | #endif
218 |
--------------------------------------------------------------------------------
/liblog2mem/log2mem_atomic.h:
--------------------------------------------------------------------------------
1 | #ifndef __MEMLOG_ATOMIC_H__
2 | #define __MEMLOG_ATOMIC_H__
3 |
4 | #include "config.h"
5 |
6 | #undef MEMLOG_HAVE_ATOMICS
7 |
8 | #ifdef HAVE___SYNC_ADD_AND_FETCH
9 | #include "log2mem_atomic_gcc.h"
10 | #elif defined (__x86_64__) || defined (__amd64__)
11 | //#include "log2mem_atomic_x86_64.h"
12 | #error "atomic functions for x86_64 not yet implemented"
13 | #elif defined (__i386) || defined (__i386__)
14 | //#include "log2mem_atomic_i386.h"
15 | #error "atomic functions for i386 not yet implemented"
16 | #endif
17 |
18 |
19 | #ifndef MEMLOG_HAVE_ATOMICS
20 | #error "atomic functions not available for your platform"
21 | #endif
22 |
23 |
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/liblog2mem/log2mem_atomic_gcc.h:
--------------------------------------------------------------------------------
1 | #ifndef __MEMLOG_ATOMIC_GNU_H__
2 | #define __MEMLOG_ATOMIC_GNU_H__
3 |
4 | #define MEMLOG_HAVE_ATOMICS 1
5 |
6 | /*
7 |
8 | Provide implementations of required atomic & synchronization operations uing
9 | GNU builtins.
10 |
11 | */
12 |
13 | // TODO: do I really need to have separate int/uint functions here?
14 |
15 | /* Increment by value and return the new value of v */
16 | static
17 | inline int log2mem_atomic_incr_fetch_int(int* v, int value)
18 | {
19 | return __sync_add_and_fetch(v, value);
20 | }
21 |
22 | static
23 | inline int log2mem_atomic_incr_fetch_uint(unsigned int* v, int value)
24 | {
25 | return __sync_add_and_fetch(v, value);
26 | }
27 |
28 |
29 | // TODO: can this be simplified? I.e., just base on atomic integers? I.e.,
30 | // implement a basic CAS loop?
31 |
32 |
33 | static
34 | inline void log2mem_atomic_spinlock(volatile int * v)
35 | {
36 | /* According to GCC documentation, will perform an acquire barrier (rather
37 | than a full barrier).
38 |
39 | This means that references after the builtin cannot move to (or be
40 | speculated to) before the builtin, but previous memory stores may not be
41 | globally visible yet, and previous memory loads may not yet be satisfied.
42 | */
43 | while( __sync_lock_test_and_set(v,1) ) {}
44 | }
45 |
46 | static
47 | inline void log2mem_atomic_spinunlock(volatile int * v)
48 | {
49 | __sync_lock_release(v);
50 | }
51 |
52 |
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/qtgui/Makefile.am:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # NOTE: it is not good practice to add "-Wall" and "-03" etc here. Those
5 | # choices should be made by the user when they invoke the configure script.
6 | AM_CPPFLAGS = -I$(top_srcdir)/liblog2mem -Wall -D_REENTRANT -fPIE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -L../liblog2mem -llog2mem
7 |
8 | AM_LDFLAGS=-pthread -lQt5Widgets -lQt5Gui -lQt5Core -lGL
9 |
10 | LDADD = -L../liblog2mem -llog2mem
11 |
12 | bin_PROGRAMS=log2memgui
13 | #noinst_PROGRAMS=server_demo
14 |
15 | # link statically for the dump tool, so that it is easier to copy around
16 | #log2memgui_LDFLAGS= -L../liblog2mem -llog2mem
17 | log2memgui_SOURCES=main.cpp qrc_resources.cc appman.cpp mainwindow.cpp tablemodel.cpp moc_mainwindow.cpp moc_tablemodel.cpp moc_appman.cpp
18 |
19 | #main.cc
20 |
21 | # log2memgui_SOURCES=main.cc \
22 | # mainwindow.cc \
23 | # moc_mainwindow.cc \
24 | # moc_tablemodel.cc \
25 | # qrc_resources.cc \
26 | # tablemodel.cc
27 |
28 |
29 | # server_dem
30 | #server_demo_SOURCES=server_demo.cc
--------------------------------------------------------------------------------
/qtgui/appman.cpp:
--------------------------------------------------------------------------------
1 | #include "appman.h"
2 | #include "mainwindow.h"
3 |
4 | AppMan::AppMan(int argc, char *argv[])
5 | : QApplication(argc, argv),
6 | m_mainwindow(NULL)
7 | {
8 |
9 | m_mainwindow = new MainWindow(this);
10 | this->setOrganizationName("QtProject");
11 | this->setApplicationName("Application Example");
12 | }
13 |
14 | //----------------------------------------------------------------------
15 | AppMan::~AppMan()
16 | {
17 | }
18 |
19 | //----------------------------------------------------------------------
20 | int AppMan::run()
21 | {
22 | m_mainwindow->show();
23 | return this->exec();
24 | }
25 |
--------------------------------------------------------------------------------
/qtgui/appman.h:
--------------------------------------------------------------------------------
1 | #ifndef APPMAN_H
2 | #define APPMAN_H
3 |
4 | #include
5 |
6 | class MainWindow;
7 |
8 | class AppMan : public QApplication
9 | {
10 | Q_OBJECT
11 | public:
12 | AppMan(int argc, char *argv[]);
13 | ~AppMan();
14 |
15 | int run();
16 |
17 | private:
18 |
19 | MainWindow * m_mainwindow;
20 | };
21 |
22 | #endif // APPMAN_H
23 |
--------------------------------------------------------------------------------
/qtgui/example1.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2014-02-15T16:14:41
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 |
9 | CONFIG += static
10 |
11 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
12 |
13 | TARGET = example1
14 | TEMPLATE = app
15 |
16 |
17 | SOURCES += main.cpp\
18 | mainwindow.cpp \
19 | tablemodel.cpp \
20 | appman.cpp
21 |
22 | HEADERS += mainwindow.h \
23 | tablemodel.h \
24 | appman.h
25 |
26 | FORMS +=
27 |
28 | RESOURCES += \
29 | resources.qrc
30 |
--------------------------------------------------------------------------------
/qtgui/example1.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {47b1c0df-5d35-4c93-a02a-3fe2d9e4712d}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | 0
45 | 8
46 | true
47 | 1
48 | true
49 | true
50 | true
51 | false
52 |
53 |
54 |
55 | ProjectExplorer.Project.PluginSettings
56 |
57 |
58 |
59 | ProjectExplorer.Project.Target.0
60 |
61 | Desktop
62 | Desktop
63 | {9a98bb76-3932-4a6f-9199-133aa45f2854}
64 | 0
65 | 0
66 | 0
67 |
68 | /home/darrens/work/dev/src/c++/log2mem/trunk/build-example1-Desktop-Debug
69 |
70 |
71 | true
72 | qmake
73 |
74 | QtProjectManager.QMakeBuildStep
75 | false
76 | true
77 |
78 | false
79 |
80 |
81 | true
82 | Make
83 |
84 | Qt4ProjectManager.MakeStep
85 |
86 | false
87 |
88 |
89 |
90 | 2
91 | Build
92 |
93 | ProjectExplorer.BuildSteps.Build
94 |
95 |
96 |
97 | true
98 | Make
99 |
100 | Qt4ProjectManager.MakeStep
101 |
102 | true
103 | clean
104 |
105 |
106 | 1
107 | Clean
108 |
109 | ProjectExplorer.BuildSteps.Clean
110 |
111 | 2
112 | false
113 |
114 | Debug
115 |
116 | Qt4ProjectManager.Qt4BuildConfiguration
117 | 2
118 | true
119 |
120 |
121 | /home/darrens/work/dev/src/c++/log2mem/trunk/build-example1-Desktop-Release
122 |
123 |
124 | true
125 | qmake
126 |
127 | QtProjectManager.QMakeBuildStep
128 | false
129 | true
130 |
131 | false
132 |
133 |
134 | true
135 | Make
136 |
137 | Qt4ProjectManager.MakeStep
138 |
139 | false
140 |
141 |
142 |
143 | 2
144 | Build
145 |
146 | ProjectExplorer.BuildSteps.Build
147 |
148 |
149 |
150 | true
151 | Make
152 |
153 | Qt4ProjectManager.MakeStep
154 |
155 | true
156 | clean
157 |
158 |
159 | 1
160 | Clean
161 |
162 | ProjectExplorer.BuildSteps.Clean
163 |
164 | 2
165 | false
166 |
167 | Release
168 |
169 | Qt4ProjectManager.Qt4BuildConfiguration
170 | 0
171 | true
172 |
173 | 2
174 |
175 |
176 | 0
177 | Deploy
178 |
179 | ProjectExplorer.BuildSteps.Deploy
180 |
181 | 1
182 | Deploy locally
183 |
184 | ProjectExplorer.DefaultDeployConfiguration
185 |
186 | 1
187 |
188 |
189 |
190 | false
191 | false
192 | false
193 | false
194 | true
195 | 0.01
196 | 10
197 | true
198 | 1
199 | 25
200 |
201 | 1
202 | true
203 | false
204 | true
205 | valgrind
206 |
207 | 0
208 | 1
209 | 2
210 | 3
211 | 4
212 | 5
213 | 6
214 | 7
215 | 8
216 | 9
217 | 10
218 | 11
219 | 12
220 | 13
221 | 14
222 |
223 | 2
224 |
225 |
226 |
227 | false
228 | %{buildDir}
229 | Custom Executable
230 |
231 | ProjectExplorer.CustomExecutableRunConfiguration
232 | 3768
233 | false
234 | true
235 | false
236 | false
237 | true
238 |
239 | 1
240 |
241 |
242 |
243 | ProjectExplorer.Project.TargetCount
244 | 1
245 |
246 |
247 | ProjectExplorer.Project.Updater.FileVersion
248 | 16
249 |
250 |
251 | Version
252 | 16
253 |
254 |
255 |
--------------------------------------------------------------------------------
/qtgui/example1.pro.user.3.2-pre1:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ProjectExplorer.Project.ActiveTarget
7 | 0
8 |
9 |
10 | ProjectExplorer.Project.EditorSettings
11 |
12 | true
13 | false
14 | true
15 |
16 | Cpp
17 |
18 | CppGlobal
19 |
20 |
21 |
22 | QmlJS
23 |
24 | QmlJSGlobal
25 |
26 |
27 | 2
28 | UTF-8
29 | false
30 | 4
31 | false
32 | true
33 | 1
34 | true
35 | 0
36 | true
37 | 0
38 | 8
39 | true
40 | 1
41 | true
42 | true
43 | true
44 | false
45 |
46 |
47 |
48 | ProjectExplorer.Project.PluginSettings
49 |
50 |
51 |
52 | ProjectExplorer.Project.Target.0
53 |
54 | Desktop
55 | Desktop
56 | {9a98bb76-3932-4a6f-9199-133aa45f2854}
57 | 0
58 | 0
59 | 0
60 |
61 | /home/darrens/work/dev/src/c++/log2mem/trunk/build-example1-Desktop-Debug
62 |
63 |
64 | true
65 | qmake
66 |
67 | QtProjectManager.QMakeBuildStep
68 | false
69 | true
70 |
71 | false
72 |
73 |
74 | true
75 | Make
76 |
77 | Qt4ProjectManager.MakeStep
78 |
79 | -w
80 | -r
81 |
82 | false
83 |
84 |
85 |
86 | 2
87 | Build
88 |
89 | ProjectExplorer.BuildSteps.Build
90 |
91 |
92 |
93 | true
94 | Make
95 |
96 | Qt4ProjectManager.MakeStep
97 |
98 | -w
99 | -r
100 |
101 | true
102 | clean
103 |
104 |
105 | 1
106 | Clean
107 |
108 | ProjectExplorer.BuildSteps.Clean
109 |
110 | 2
111 | false
112 |
113 | Debug
114 |
115 | Qt4ProjectManager.Qt4BuildConfiguration
116 | 2
117 | true
118 |
119 |
120 | /home/darrens/work/dev/src/c++/log2mem/trunk/build-example1-Desktop-Release
121 |
122 |
123 | true
124 | qmake
125 |
126 | QtProjectManager.QMakeBuildStep
127 | false
128 | true
129 |
130 | false
131 |
132 |
133 | true
134 | Make
135 |
136 | Qt4ProjectManager.MakeStep
137 |
138 | -w
139 | -r
140 |
141 | false
142 |
143 |
144 |
145 | 2
146 | Build
147 |
148 | ProjectExplorer.BuildSteps.Build
149 |
150 |
151 |
152 | true
153 | Make
154 |
155 | Qt4ProjectManager.MakeStep
156 |
157 | -w
158 | -r
159 |
160 | true
161 | clean
162 |
163 |
164 | 1
165 | Clean
166 |
167 | ProjectExplorer.BuildSteps.Clean
168 |
169 | 2
170 | false
171 |
172 | Release
173 |
174 | Qt4ProjectManager.Qt4BuildConfiguration
175 | 0
176 | true
177 |
178 | 2
179 |
180 |
181 | 0
182 | Deploy
183 |
184 | ProjectExplorer.BuildSteps.Deploy
185 |
186 | 1
187 | Deploy locally
188 |
189 | ProjectExplorer.DefaultDeployConfiguration
190 |
191 | 1
192 |
193 |
194 |
195 | false
196 | false
197 | false
198 | false
199 | true
200 | 0.01
201 | 10
202 | true
203 | 1
204 | 25
205 |
206 | 1
207 | true
208 | false
209 | true
210 | valgrind
211 |
212 | 0
213 | 1
214 | 2
215 | 3
216 | 4
217 | 5
218 | 6
219 | 7
220 | 8
221 | 9
222 | 10
223 | 11
224 | 12
225 | 13
226 | 14
227 |
228 | 2
229 |
230 | example1
231 |
232 | Qt4ProjectManager.Qt4RunConfiguration:/home/darrens/work/dev/src/c++/log2mem/trunk/qtgui/example1.pro
233 |
234 | example1.pro
235 | false
236 | false
237 |
238 | 3768
239 | true
240 | false
241 | false
242 | false
243 | true
244 |
245 | 1
246 |
247 |
248 |
249 | ProjectExplorer.Project.TargetCount
250 | 1
251 |
252 |
253 | ProjectExplorer.Project.Updater.EnvironmentId
254 | {47b1c0df-5d35-4c93-a02a-3fe2d9e4712d}
255 |
256 |
257 | ProjectExplorer.Project.Updater.FileVersion
258 | 15
259 |
260 |
261 |
--------------------------------------------------------------------------------
/qtgui/images/copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/copy.png
--------------------------------------------------------------------------------
/qtgui/images/cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/cut.png
--------------------------------------------------------------------------------
/qtgui/images/new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/new.png
--------------------------------------------------------------------------------
/qtgui/images/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/open.png
--------------------------------------------------------------------------------
/qtgui/images/paste.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/paste.png
--------------------------------------------------------------------------------
/qtgui/images/save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrenjs/log2mem/bdcf45494c66c1139e8c5e3a1cab87f9a476f27d/qtgui/images/save.png
--------------------------------------------------------------------------------
/qtgui/main.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "appman.h"
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | AppMan myapp(argc, argv);
7 | myapp.run();
8 | }
9 |
--------------------------------------------------------------------------------
/qtgui/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "tablemodel.h"
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | //----------------------------------------------------------------------
11 | MainWindow::MainWindow(AppMan* appman)
12 | : QMainWindow(NULL),
13 | m_model(NULL),
14 | m_appman(appman)
15 | {
16 | m_treeView = new QTableView();
17 |
18 | m_model = new TableModel(m_appman);
19 |
20 | m_treeView->setModel(m_model);
21 | m_treeView->resizeColumnsToContents();
22 | m_treeView->verticalHeader()->hide();
23 |
24 | QStringList headers;
25 | headers << tr("Title") << tr("Description");
26 | m_textEdit = new QPlainTextEdit();
27 |
28 | // setCentralWidget(m_textEdit);
29 | setCentralWidget(m_treeView);
30 |
31 | createActions();
32 | createMenus();
33 | createStatusBar();
34 | }
35 |
36 | //----------------------------------------------------------------------
37 | MainWindow::~MainWindow()
38 | {
39 | }
40 |
41 | //----------------------------------------------------------------------
42 | void MainWindow::createMenus()
43 | {
44 | fileMenu = menuBar()->addMenu(tr("&File"));
45 | fileMenu->addAction(openAct);
46 | fileMenu->addAction(refreshAct);
47 | fileMenu->addSeparator();
48 | fileMenu->addAction(exitAct);
49 |
50 |
51 | editMenu = menuBar()->addMenu(tr("&Edit"));
52 | editMenu->addAction(cutAct);
53 | editMenu->addAction(copyAct);
54 | editMenu->addAction(pasteAct);
55 |
56 | menuBar()->addSeparator();
57 |
58 | helpMenu = menuBar()->addMenu(tr("&Help"));
59 | helpMenu->addAction(aboutAct);
60 | helpMenu->addAction(aboutQtAct);
61 | }
62 |
63 | //----------------------------------------------------------------------
64 | void MainWindow::createActions()
65 |
66 | {
67 | openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this);
68 | openAct->setShortcuts(QKeySequence::Open);
69 | openAct->setStatusTip(tr("Open an existing file"));
70 | connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
71 |
72 |
73 | refreshAct = new QAction(QIcon(":/images/open.png"), tr("&Refresh"), this);
74 | // refreshAct->setShortcuts(QKeySequence::Open);
75 | refreshAct->setStatusTip(tr("Refresh"));
76 | connect(refreshAct,
77 | SIGNAL(triggered()),
78 | this,
79 | SLOT(slot_refresh()));
80 |
81 |
82 | exitAct = new QAction(tr("E&xit"), this);
83 | exitAct->setShortcuts(QKeySequence::Quit);
84 | exitAct->setStatusTip(tr("Exit the application"));
85 | connect(exitAct,
86 | SIGNAL( triggered() ),
87 | this,
88 | SLOT( close() )
89 | );
90 |
91 |
92 | cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);
93 | cutAct->setShortcuts(QKeySequence::Cut);
94 | cutAct->setStatusTip(tr("Cut the current selection's contents to the "
95 | "clipboard"));
96 |
97 | // TODO: DJS: put back
98 | //connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
99 |
100 | copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this);
101 | copyAct->setShortcuts(QKeySequence::Copy);
102 | copyAct->setStatusTip(tr("Copy the current selection's contents to the "
103 | "clipboard"));
104 | // TODO: DJS: put back
105 | // connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
106 |
107 | pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this);
108 | pasteAct->setShortcuts(QKeySequence::Paste);
109 | pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
110 | "selection"));
111 |
112 | // TODO: DJS: put back
113 | // connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));
114 |
115 | aboutAct = new QAction(tr("&About"), this);
116 | aboutAct->setStatusTip(tr("Show the application's About box"));
117 | connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
118 |
119 |
120 | aboutQtAct = new QAction(tr("About &Qt"), this);
121 | aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
122 | connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
123 |
124 |
125 | cutAct->setEnabled(false);
126 | copyAct->setEnabled(false);
127 |
128 | // TODO: DJS: put back
129 | // connect(textEdit, SIGNAL(copyAvailable(bool)),
130 | // cutAct, SLOT(setEnabled(bool)));
131 | // connect(textEdit, SIGNAL(copyAvailable(bool)),
132 | // copyAct, SLOT(setEnabled(bool)));
133 | }
134 |
135 | //----------------------------------------------------------------------
136 | void MainWindow::about()
137 |
138 | {
139 | QMessageBox::about(this, tr("About Application"),
140 | tr("The Application example demonstrates how to "
141 | "write modern GUI applications using Qt, with a menu bar, "
142 | "toolbars, and a status bar."));
143 | }
144 |
145 | //----------------------------------------------------------------------
146 | void MainWindow::open()
147 | {
148 | QString fileName = QFileDialog::getOpenFileName(this);
149 | // if (!fileName.isEmpty())
150 | // loadFile(fileName);
151 | }
152 |
153 | //----------------------------------------------------------------------
154 | void MainWindow::createStatusBar()
155 | {
156 | statusBar()->showMessage(tr("Ready"));
157 | }
158 |
159 | //----------------------------------------------------------------------
160 | void MainWindow::slot_refresh()
161 | {
162 | m_model->refresh();
163 | }
164 |
--------------------------------------------------------------------------------
/qtgui/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 |
6 | QT_BEGIN_NAMESPACE
7 | class QAction;
8 | class QMenu;
9 | class QPlainTextEdit;
10 | class QTableView;
11 | class QAbstractItemModel;
12 | QT_END_NAMESPACE
13 |
14 | class TableModel;
15 | class AppMan;
16 |
17 | class MainWindow : public QMainWindow
18 | {
19 | Q_OBJECT
20 |
21 | public:
22 | explicit MainWindow(AppMan*);
23 | ~MainWindow();
24 |
25 | private slots:
26 | // void newFile();
27 | void open();
28 | void slot_refresh();
29 | // bool save();
30 | // bool saveAs();
31 | void about();
32 | // void documentWasModified();
33 |
34 | private:
35 | // Ui::MainWindow *ui;
36 |
37 | void createActions();
38 | void createMenus();
39 | void createToolBars();
40 | void createStatusBar();
41 |
42 | QMenu *fileMenu;
43 | QMenu *editMenu;
44 | QMenu *helpMenu;
45 | QAction *openAct;
46 | QAction *refreshAct;
47 | QAction *exitAct;
48 | QAction *cutAct;
49 | QAction *copyAct;
50 | QAction *pasteAct;
51 | QAction *aboutAct;
52 | QAction *aboutQtAct;
53 | QPlainTextEdit* m_textEdit;
54 | QTableView* m_treeView;
55 | TableModel* m_model;
56 |
57 | AppMan* m_appman;
58 | };
59 |
60 | #endif // MAINWINDOW_H
61 |
--------------------------------------------------------------------------------
/qtgui/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | images/copy.png
4 | images/cut.png
5 | images/new.png
6 | images/open.png
7 | images/paste.png
8 | images/save.png
9 |
10 |
11 |
--------------------------------------------------------------------------------
/qtgui/tablemodel.cpp:
--------------------------------------------------------------------------------
1 | #include "tablemodel.h"
2 | #include "appman.h"
3 |
4 | #include "log2mem/log2mem_dev.h"
5 |
6 | #include
7 |
8 |
9 |
10 | //----------------------------------------------------------------------
11 | TableModel::TableModel(AppMan* appman)
12 | : QAbstractTableModel(NULL),
13 | m_appman(appman)
14 | {
15 | refresh();
16 |
17 | this->setHeaderData(0, Qt::Horizontal, tr("ID"));
18 | this->setHeaderData(1, Qt::Horizontal, tr("First name"));
19 | this->setHeaderData(2, Qt::Horizontal, tr("Last name"));
20 | }
21 |
22 | //----------------------------------------------------------------------
23 | QVariant TableModel::headerData(int section,
24 | Qt::Orientation orientation,
25 | int role) const
26 | {
27 | if (role != Qt::DisplayRole)
28 | return QVariant();
29 |
30 | if (orientation == Qt::Horizontal)
31 | {
32 | switch (section)
33 | {
34 | case MemmapID: return tr("id");
35 | case Typename: return tr("type");
36 | case Label: return tr("label");
37 | case Value: return tr("value");
38 | default: Q_ASSERT(false);
39 | }
40 | }
41 |
42 | return section + 1;
43 | }
44 |
45 | //----------------------------------------------------------------------
46 | QVariant TableModel::data(const QModelIndex &index,
47 | int role ) const
48 | {
49 | QString MaxZipcode = "xxxxx";
50 | if (!index.isValid() ||
51 | index.row() < 0 || index.row() >= m_data.count() ||
52 | index.column() < 0 || index.column() >= NumColumns)
53 | return QVariant();
54 |
55 | const TableModelItem &item = m_data.at(index.row());
56 |
57 | if (role == Qt::SizeHintRole)
58 | {
59 | QStyleOptionComboBox option;
60 |
61 | switch (index.column())
62 | {
63 | case MemmapID:
64 | {
65 | option.currentText = MaxZipcode;
66 | const QString header = headerData(MemmapID,
67 | Qt::Horizontal,
68 | Qt::DisplayRole).toString();
69 | if (header.length() > option.currentText.length())
70 | option.currentText = header;
71 | break;
72 | }
73 | case Typename:
74 | {
75 | option.currentText = item.type;
76 | break;
77 | }
78 | case Label: option.currentText = item.label; break;
79 | case Value: option.currentText = item.value; break;
80 | default: Q_ASSERT(false);
81 | }
82 |
83 | QFontMetrics fontMetrics(data(index, Qt::FontRole)
84 | .value());
85 | option.fontMetrics = fontMetrics;
86 | QSize size(fontMetrics.width(option.currentText),
87 | fontMetrics.height());
88 |
89 | return m_appman->style()->sizeFromContents(QStyle::CT_ComboBox,
90 | &option, size);
91 | }
92 |
93 | if (role == Qt::DisplayRole || role == Qt::EditRole)
94 | {
95 | switch (index.column())
96 | {
97 | case MemmapID : return item.rowid;
98 | case Typename : return item.type;
99 | case Label : return item.label;
100 | case Value : return item.value;
101 | default: Q_ASSERT(false);
102 | }
103 | }
104 |
105 | // for all unhandled cases
106 | return QVariant();
107 | }
108 |
109 | //----------------------------------------------------------------------
110 | void TableModel::refresh()
111 | {
112 | TableModelItem item;
113 | item.rowid = "1";
114 | item.type = "1";
115 | item.label = "enable";
116 | item.value = "2.32";
117 |
118 | int newrows_firstindex = m_data.count();
119 | int newrows_lastindex = m_data.count();
120 |
121 | this->beginInsertRows(QModelIndex(), newrows_firstindex, newrows_lastindex);
122 | m_data.push_back( item );
123 | this->endInsertRows();
124 |
125 | }
126 |
127 | //----------------------------------------------------------------------
128 | int TableModel::rowCount(const QModelIndex & index) const
129 | {
130 | return index.isValid() ? 0 : m_data.count();
131 | }
132 |
133 | //----------------------------------------------------------------------
134 | int TableModel::columnCount(const QModelIndex & index) const
135 | {
136 | return 4;
137 | }
138 |
139 | //----------------------------------------------------------------------
140 | void TableModel::rebuild_table()
141 | {
142 | /*
143 | NOTE: not using the beginResetModel & endResetModel methods, because it
144 | will cause all table sections, and scroll positions, to be lost.
145 |
146 | this->beginResetModel();
147 | this->endResetModel();
148 | */
149 | struct log2mem_handle * handle = 0;
150 |
151 | const char* filename="/tmp/log2mem.dat";
152 | handle = log2mem_attach(filename);
153 |
154 |
155 | unsigned int num_vars = handle->header->config.num_vars;
156 |
157 |
158 | /*
159 | get a variable: index; type; ... index is the key item.
160 |
161 |
162 |
163 | 1.double.=1.1
164 |
165 | does [i] exist? NO: --> insert
166 | YES: --> changed?
167 |
168 |
169 |
170 | */
171 |
172 | // this->beginInsertRows(QModelIndex(), newrows_firstindex, newrows_lastindex);
173 | // m_data.push_back( item );
174 | // this->endInsertRows();
175 |
176 | // TODO: scan the memory map, looking for the current contents.
177 |
178 | // TODO: merge in the changes, which causes either row inserts, row
179 | // deletions, or row changes.
180 | }
181 |
--------------------------------------------------------------------------------
/qtgui/tablemodel.h:
--------------------------------------------------------------------------------
1 | #ifndef TABLEMODEL_H
2 | #define TABLEMODEL_H
3 |
4 | #include
5 | #include
6 |
7 |
8 | class AppMan;
9 |
10 | struct TableModelItem
11 | {
12 | QString rowid;
13 | QString type;
14 | QString label;
15 | QString value;
16 | };
17 |
18 | class TableModel : public QAbstractTableModel
19 | {
20 | Q_OBJECT
21 | public:
22 |
23 |
24 | enum Column {MemmapID, Typename, Label, Value};
25 |
26 | static const int NumColumns = 4;
27 |
28 | TableModel(AppMan*);
29 |
30 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
31 |
32 | virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
33 |
34 | virtual QVariant data(const QModelIndex &index,
35 | int role = Qt::DisplayRole) const;
36 |
37 | virtual QVariant headerData(int section,
38 | Qt::Orientation orientation,
39 | int role) const;
40 |
41 | void refresh();
42 | void rebuild_table();
43 |
44 | void insert();
45 | private:
46 | AppMan* m_appman;
47 | QList m_data;
48 | };
49 |
50 | #endif // TABLEMODEL_H
51 |
--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 |
4 | echo "===== Autoconf setup script ====="
5 |
6 | autoreconf -fiv
--------------------------------------------------------------------------------
/util/Makefile.am:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # NOTE: it is not good practice to add "-Wall" and "-03" etc here. Those
5 | # choices should be made by the user when they invoke the configure script.
6 | AM_CPPFLAGS = -I$(top_srcdir)/liblog2mem -Wall
7 |
8 | AM_LDFLAGS=
9 |
10 | LDADD = -L../liblog2mem -llog2mem -lrt
11 |
12 | bin_PROGRAMS=log2mem-util
13 | #noinst_PROGRAMS=server_demo
14 |
15 | # link statically for the dump tool, so that it is easier to copy around
16 | log2mem_util_LDFLAGS=-static
17 | log2mem_util_SOURCES=log2memutil.c
18 |
19 | # server_dem
20 | #server_demo_SOURCES=server_demo.cc
21 |
--------------------------------------------------------------------------------
/util/log2memutil.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013, Darren Smith
3 |
4 | This file is part of log2mem, a library for providing high performance
5 | logging, timing and debugging to applications.
6 |
7 | log2mem is free software: you can redistribute it and/or modify it under the
8 | terms of the GNU General Public License as published by the Free Software
9 | Foundation, either version 3 of the License, or (at your option) any later
10 | version.
11 |
12 | log2mem is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with log2mem. If not, see .
19 | */
20 |
21 | #include "log2mem/log2mem_dev.h"
22 | #include "config.h"
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | const char* g_delim = " ";
30 | int g_showdelim = 1;
31 | int g_terse = 0;
32 |
33 | /* struct set_var_double */
34 | /* { */
35 | /* char type; */
36 | /* unsigned int idx; */
37 | /* double value; */
38 | /* }; */
39 |
40 | /* struct node */
41 | /* { */
42 | /* void * data; */
43 | /* struct node * next; */
44 | /* struct node * prev; */
45 | /* }; */
46 |
47 |
48 | /* struct nodelist */
49 | /* { */
50 | /* struct node* begin; */
51 | /* struct node* end; /\* immutable *\/ */
52 | /* }; */
53 |
54 |
55 | /* void list_init(struct nodelist * l) */
56 | /* { */
57 | /* l->begin = (struct node*) malloc(sizeof(struct node)); */
58 | /* l->end = l->begin; */
59 |
60 | /* memset(l->end, 0, sizeof(struct node)); */
61 | /* l->end->next = l->end; */
62 | /* l->end->prev = l->prev; */
63 | /* } */
64 |
65 | /* void list_push_back(struct nodelist * nl, void* data) */
66 | /* { */
67 | /* // create new node */
68 | /* struct node * nodeptr = (struct node*) malloc(sizeof(struct node)); */
69 | /* memset(nodeptr, 0, sizeof(struct node)); */
70 | /* nodeptr->data = data; */
71 |
72 | /* // insert into list */
73 | /* nodeptr->next = l->end; */
74 | /* nodeptr->prev = end->prev; */
75 | /* } */
76 |
77 | /* struct nodelist g_list; */
78 |
79 |
80 |
81 | #undef PFSIZET
82 | #if defined __x86_64__ || defined __LP64__
83 | #define PFSIZET "%lu"
84 | #else
85 | #define PFSIZET "%u"
86 | #endif
87 |
88 | #define OPT_DOUBLE "--double"
89 | #define OPT_STRING "--string"
90 | #define OPT_INT "--int"
91 |
92 | //----------------------------------------------------------------------
93 | void help()
94 | {
95 | printf("usage: log2mem-dump [MEMMAP-FILE] [OPTIONS]\n");
96 | printf("\n");
97 | printf("Options\n");
98 | printf(" -s\t\t\tshow memmap summary\n");
99 | printf(" -c\t\t\tshow counters\n");
100 | printf(" -r\t\t\tshow rows\n");
101 | printf(" -v\t\t\tshow variables\n");
102 | printf(" -a\t\t\tshow all data sections\n");
103 | printf(" -F DELIM \t\tuse DELIM as output delimiter for data values\n");
104 | printf(" -z\t\t\tsuppress delimiter\n");
105 | printf(" -t\t\t\tterse, only print data values\n");
106 | printf(" " OPT_DOUBLE "[I]=N\t\tset var double[I] to value N\n");
107 | printf(" " OPT_INT "[I]=N\t\tset var int[I] to value N\n");
108 | printf(" --NAME=N\t\tset var with name NAME to value N\n");
109 | printf(" --version\t\tversion info\n");
110 | exit(0);
111 | }
112 | //----------------------------------------------------------------------
113 | void die(const char* msg, const char * msg2)
114 | {
115 | if (msg2==0) msg2="";
116 | printf("%s%s\n", msg,msg2);
117 | exit(1);
118 | }
119 |
120 | //----------------------------------------------------------------------
121 | void print_summary(struct log2mem_handle * handle)
122 | {
123 | if (!handle)
124 | return;
125 |
126 | struct log2mem_layout layout;
127 | log2mem_calculate_layout(&handle->header->config, &layout);
128 |
129 | printf("Memmap configuration\n--------------------\n");
130 |
131 | printf("created: %s\n", handle->header->datecreated);
132 | printf("options: ");
133 | const char* delim="";
134 | if (handle->header->config.options & MEMLOG_FILELINE)
135 | {
136 | printf("%s%s", delim, "MEMLOG_FILE_LINE");
137 | delim = ",";
138 | }
139 | if (handle->header->config.options & MEMLOG_THREADID)
140 | {
141 | printf("%s%s", delim, "MEMLOG_THREADID");
142 | delim = ",";
143 | }
144 |
145 | /* time */
146 | switch(handle->header->config.options & MEMLOG_CLOCKSOURCE_MASK)
147 | {
148 | case MEMLOG_RDTSC : {
149 | printf("%s%s", delim, "MEMLOG_RDTSC");
150 | delim = ",";
151 | break;
152 | }
153 | case MEMLOG_GETTIMEOFDAY : {
154 | printf("%s%s", delim, "MEMLOG_GETTIMEOFDAY");
155 | delim = ",";
156 | break;
157 | };
158 | case MEMLOG_CLOCKGETTIME : {
159 | printf("%s%s", delim, "MEMLOG_CLOCKGETTIME");
160 | delim = ",";
161 | break;
162 | };
163 | };
164 |
165 | printf("\n");
166 |
167 | printf("number of counters: %d\n", handle->header->config.num_counters);
168 | printf("number of rows: %d\n", handle->header->config.num_rows);
169 | printf("number of vars %d\n", handle->header->config.num_vars);
170 | printf("row data size: %d\n", handle->header->config.row_len);
171 | printf("row total size: " PFSIZET "\n",
172 | calc_row_total_size(&handle->header->config));
173 | printf("next rowid: %d\n", handle->header->nextrow);
174 |
175 | printf("\nMemmap architecture\n-------------------\n");
176 |
177 | printf("version: %d\n", handle->header->version);
178 | printf("arch: %d\n", handle->header->arch);
179 | printf("endian: %s\n", ((handle->header->flags & 0x1)? "little":"big"));
180 |
181 | printf("\nSection offsets & size\n----------------------\n");
182 | printf("header: %u\n", 0);
183 | printf("counters: %u\n", layout.counters_off);
184 | printf("rows: %u\n", layout.rows_off);
185 | printf("labels: %u\n", layout.counter_labels_off);
186 | printf("double_vars: %u\n", layout.double_vars_off);
187 | printf("int_vars: %u\n", layout.int_vars_off);
188 | printf("memmap size: %u\n", layout.size);
189 |
190 | printf("\nFixed structure sizes\n---------------------\n");
191 | printf("MEMLOG_MM_HEADER_SIZE: %d\n", MEMLOG_MM_HEADER_SIZE);
192 | printf("MEMLOG_LABEL_LEN: %d\n", MEMLOG_LABEL_LEN);
193 | printf("sizeof(log2mem_mm_header): " PFSIZET "\n", sizeof(struct log2mem_mm_header));
194 | printf("sizeof(log2mem_data_hdr): " PFSIZET "\n", sizeof(struct log2mem_data_hdr));
195 | printf("sizeof(log2mem_row): " PFSIZET "\n", sizeof(struct log2mem_row));
196 | printf("sizeof(log2mem_counter): " PFSIZET "\n", sizeof(struct log2mem_counter));
197 | printf("sizeof(log2mem_var_double): " PFSIZET "\n", sizeof(struct log2mem_var_double));
198 | printf("sizeof(log2mem_var_int): " PFSIZET "\n", sizeof(struct log2mem_var_int));
199 | }
200 | //----------------------------------------------------------------------
201 | void print_counters(struct log2mem_handle * handle)
202 | {
203 | if (!handle) return;
204 |
205 | char label[ MEMLOG_LABEL_LEN +1];
206 |
207 | struct log2mem_counter * c = handle->counters;
208 | struct log2mem_label * l = handle->counter_labels;
209 |
210 | const int num_counters = handle->header->config.num_counters;
211 | int i;
212 | for (i=0; i < num_counters; ++i, ++c, ++l)
213 | {
214 | if (c->used)
215 | {
216 | // reset the label
217 | memset(label, 0, sizeof(label));
218 | strcpy(label, "noname");
219 | if (l) strncpy(label, l->text, MEMLOG_LABEL_LEN);
220 |
221 | printf("counter[%d] %s : %d\n", i, label, c->value.v);
222 | }
223 | }
224 |
225 | }
226 |
227 | //----------------------------------------------------------------------
228 | void print_vars(struct log2mem_handle * handle)
229 | {
230 | if (!handle) return;
231 |
232 | struct log2mem_var_double * var_double = handle->double_vars;
233 |
234 | int i;
235 | for (i=0; i < handle->header->config.num_vars; ++i, ++var_double)
236 | {
237 | if (var_double->flags & log2mem_eUsed)
238 | {
239 | printf("double[%d] %s%s: %f\n", i, var_double->text,
240 | (strlen(var_double->text)? " ": ""), var_double->value);
241 | }
242 | }
243 |
244 | struct log2mem_var_int * var_int = handle->int_vars;
245 | for (i=0; i < handle->header->config.num_vars; ++i, ++var_int)
246 | {
247 | if (var_int->flags & log2mem_eUsed)
248 | {
249 | printf("int[%d] %s%s: %i\n", i, var_int->text,
250 | (strlen(var_int->text)? " ": ""), var_int->value);
251 | }
252 | }
253 |
254 | }
255 | //----------------------------------------------------------------------
256 | void print_rows(struct log2mem_handle * handle)
257 | {
258 | if (!handle) return;
259 |
260 | const int num_rows = handle->header->config.num_rows;
261 | const int row_total_size = calc_row_total_size(&handle->header->config);
262 | char* rowstart = (char*) handle->rows;
263 | unsigned int i;
264 |
265 | /* scan all the rows, looking for the lowest rowid */
266 | unsigned int lowest_rowid = ~0;
267 | for (i = 0; i < num_rows; ++i)
268 | {
269 | struct log2mem_row * r = (struct log2mem_row *)
270 | (rowstart+i*row_total_size);
271 |
272 | if (r->id <= lowest_rowid) lowest_rowid = r->id;
273 | }
274 |
275 | /* print all rows, starting at the row with lowest rowid */
276 | unsigned int next_rowid = lowest_rowid;
277 | for (i = 0; i < num_rows; ++i, ++next_rowid)
278 | {
279 | unsigned int rowidx = next_rowid & (handle->header->config.num_rows-1);
280 | struct log2mem_row * r = (struct log2mem_row *)
281 | (rowstart+rowidx*row_total_size);
282 |
283 | if (r->datalen == 0) continue;
284 |
285 |
286 | if (!g_terse)
287 | {
288 | printf("%i ", r->id);
289 |
290 |
291 | switch(handle->header->config.options & MEMLOG_CLOCKSOURCE_MASK)
292 | {
293 | case MEMLOG_RDTSC : {
294 | // TODO: how to convert from tsc to cpu resolution?
295 | uint64_t tsc = r->ts;
296 | printf("%lu ", tsc);
297 | break;
298 | }
299 | case MEMLOG_GETTIMEOFDAY : {
300 | struct timeval __tval;
301 | log2mem_ts_to_timeval(r->ts, &__tval);
302 |
303 | struct tm _tm;
304 | localtime_r(&__tval.tv_sec, &_tm);
305 |
306 | printf("%02d:%02d:%02d.%06lu ", _tm.tm_hour, _tm.tm_min, _tm.tm_sec,
307 | __tval.tv_usec);
308 | break;
309 | };
310 | case MEMLOG_CLOCKGETTIME : {
311 | struct timespec __timespec;
312 | log2mem_ts_to_timespec(r->ts, &__timespec);
313 |
314 | struct tm _tm;
315 | localtime_r(&__timespec.tv_sec, &_tm);
316 |
317 | printf("%02d:%02d:%02d.%09lu ", _tm.tm_hour, _tm.tm_min, _tm.tm_sec,
318 | __timespec.tv_nsec);
319 | break;
320 | };
321 | };
322 |
323 | if (handle->header->config.options & MEMLOG_THREADID)
324 | printf("[%i] ", r->tid);
325 | }
326 |
327 | int i = 0;
328 | int wantdelim = 0;
329 |
330 | const char* rowdata = log2mem_row_payload(r);
331 | while (i < r->datalen)
332 | {
333 | struct log2mem_data_hdr * hdr = (struct log2mem_data_hdr *) (rowdata+i);
334 | const char* data = rowdata + i + sizeof(struct log2mem_data_hdr);
335 |
336 | // printf("[type %d, datalen %d]", hdr->type, hdr->len);
337 |
338 | if (g_showdelim && wantdelim)
339 | printf("%s", g_delim);
340 | else
341 | wantdelim=1;
342 |
343 | // TODO: only show this for debug runs
344 | //printf("[hdr type=%d, len=%d] ", hdr->type, hdr->len);
345 |
346 | switch (hdr->type)
347 | {
348 | case MEMLOG_DATATYPE_FILENAME:
349 | {
350 | if (!g_terse)
351 | {
352 | const char * s = (const char *) data;
353 | printf("(%s:", s);
354 | }
355 | wantdelim=0; /* suppress next delimiter */
356 | break;
357 | }
358 | case MEMLOG_DATATYPE_LINENO:
359 | {
360 | if (!g_terse)
361 | {
362 | const int * d = (const int *) data;
363 | printf("%d) ", *d);
364 | }
365 | wantdelim=0; /* suppress next delimiter */
366 | break;
367 | }
368 | case MEMLOG_DATATYPE_STRING:
369 | {
370 | const char * s = (const char *) data;
371 | printf("%s", s);
372 | break;
373 | }
374 | case MEMLOG_DATATYPE_UINT:
375 | {
376 | const unsigned int * d = (const unsigned int *) data;
377 | printf("%u", *d);
378 | break;
379 | }
380 | case MEMLOG_DATATYPE_INT:
381 | {
382 | const int * d = (const int *) data;
383 | printf("%d", *d);
384 | break;
385 | }
386 | case MEMLOG_DATATYPE_ULONG:
387 | {
388 | const unsigned long * d = (const unsigned long *) data;
389 | printf("%lu", *d);
390 | break;
391 | }
392 | case MEMLOG_DATATYPE_LONG:
393 | {
394 | const long * d = (const long *) data;
395 | printf("%ld", *d);
396 | break;
397 | }
398 |
399 | case MEMLOG_DATATYPE_FLOAT:
400 | {
401 | const float * d = (const float *) data;
402 | printf("%f", *d);
403 | break;
404 | }
405 | case MEMLOG_DATATYPE_DOUBLE:
406 | {
407 | const double * d = (const double *) data;
408 | printf("%f", *d);
409 | break;
410 | }
411 | case MEMLOG_DATATYPE_CHAR:
412 | {
413 | const char * d = (const char *) data;
414 | printf("%c", *d);
415 | break;
416 | }
417 | }
418 | i += hdr->len;
419 | }
420 |
421 |
422 |
423 | printf("\n");
424 | }
425 |
426 |
427 | }
428 |
429 | //----------------------------------------------------------------------
430 |
431 | /*
432 | argc,argv : command line args
433 | argi : index of next arg, can be modified by this function
434 | idx,value : var index & value
435 | */
436 | void process_set_var_arg(int argc, const char** argv, int * argi,
437 | unsigned int* idx, const char** value,
438 | const char* optionprefix)
439 | {
440 | const char* firstarg = argv[*argi];
441 |
442 | *idx = 0;
443 | const char * ptr = firstarg+strlen(optionprefix);
444 |
445 | if (*ptr == '[') ptr++; /* optional bracket */
446 |
447 | while ( *ptr && (*ptr >= '0') && (*ptr <= '9') )
448 | {
449 | *idx = (10 * *idx) + (*ptr - '0');
450 | ptr++;
451 | }
452 |
453 | if (*ptr == ']') ptr++; /* optional bracket */
454 |
455 | if (*ptr == '=')
456 | {
457 | ptr++;
458 | }
459 | else if (*ptr != '\0')
460 | {
461 | die("expected numeric digits, ", firstarg);
462 | }
463 | else
464 | {
465 | if (++*argi >= argc) die("missing argument to ", firstarg);
466 | ptr = argv[*argi];
467 | }
468 |
469 | *value = ptr;
470 | }
471 |
472 | //----------------------------------------------------------------------
473 | void set_var_string(int argc, const char** argv, int * i,
474 | struct log2mem_handle * handle)
475 | {
476 | unsigned int idx = 0;
477 | const char * ptr = 0;
478 | process_set_var_arg(argc, argv, i, &idx, &ptr, OPT_STRING);
479 |
480 | if (!handle) return;
481 | /*
482 | double val;
483 | sscanf(ptr, "%lf", &val);
484 | printf("setting double[%u]=%lf\n", idx, val);
485 | log2mem_var_set_double(idx, val);
486 | */
487 | }
488 |
489 | //----------------------------------------------------------------------
490 |
491 | void set_var_double(int argc, const char** argv, int * i,
492 | struct log2mem_handle * handle)
493 | {
494 | unsigned int idx = 0;
495 | const char * ptr = 0;
496 | process_set_var_arg(argc, argv, i, &idx, &ptr, OPT_DOUBLE);
497 |
498 | if (!handle) return;
499 |
500 | double val;
501 | sscanf(ptr, "%lf", &val);
502 | log2mem_var_double_set(idx, val);
503 | }
504 |
505 | //----------------------------------------------------------------------
506 |
507 | void set_var_int(int argc, const char** argv, int * i,
508 | struct log2mem_handle * handle)
509 | {
510 | unsigned int idx = 0;
511 | const char * ptr = 0;
512 | process_set_var_arg(argc, argv, i, &idx, &ptr, OPT_INT);
513 |
514 | if (!handle) return;
515 |
516 | int val;
517 | sscanf(ptr, "%i", &val);
518 | log2mem_var_int_set(idx, val);
519 | }
520 |
521 | //----------------------------------------------------------------------
522 |
523 | void set_var_by_name(int argc, const char** argv, int * argi,
524 | struct log2mem_handle * handle)
525 | {
526 | const char* firstptr = argv[*argi];
527 | const char* firstarg = argv[*argi]+2; /* skip the '--' */
528 |
529 | char * argdup = 0;
530 | const char * label;
531 | const char* p = strchr(firstarg, '=');
532 |
533 | if (p)
534 | {
535 | argdup = strdup(firstarg);
536 | argdup[p - firstarg] = '\0';
537 | label=argdup;
538 | p++;
539 | }
540 | else
541 | {
542 | ++*argi;
543 | if (*argi >= argc)
544 | die("missing argument after ", firstptr);
545 |
546 | label=firstarg;
547 | p=argv[*argi];
548 | }
549 |
550 | /* don't proceed past argument parsing, in parse-only mode*/
551 | if (!handle) return;
552 |
553 | //printf("trying to set label[%s] to [%s]\n", label, p);
554 |
555 | if (label[0] == '\0') return;
556 |
557 | int i;
558 | int found=0;
559 | /* search doubles */
560 | struct log2mem_var_double * var_double = handle->double_vars;
561 | for (i=0; i < handle->header->config.num_vars; ++i, ++var_double)
562 | {
563 | if ((var_double->flags & log2mem_eUsed) &&
564 | (strcmp(label, var_double->text)==0))
565 | {
566 | sscanf(p, "%lf", &var_double->value);
567 | found=1;
568 | }
569 | }
570 |
571 | /* search ints */
572 | struct log2mem_var_int * var_int = handle->int_vars;
573 | for (i=0; i < handle->header->config.num_vars; ++i, ++var_int)
574 | {
575 | if ((var_int->flags & log2mem_eUsed) &&
576 | (strcmp(label, var_int->text)==0))
577 | {
578 | sscanf(p, "%i", &var_int->value);
579 | found=1;
580 | }
581 | }
582 |
583 | if (!found) printf("warning, no variable found with name \"%s\"\n", label);
584 |
585 | free(argdup);
586 | }
587 |
588 | //----------------------------------------------------------------------
589 | const char* parse_args(int argc, const char** argv, int parseonly,
590 | struct log2mem_handle * handle)
591 | {
592 | int i = 1;
593 | const char* filename = 0;
594 | int defaultshow = 1;
595 |
596 | enum showbits
597 | {
598 | eSummary = 0x01,
599 | eCounters = 0x02,
600 | eRows = 0x04,
601 | eVars = 0x08
602 | };
603 | int toshow = 0;
604 |
605 | for (;i < argc; i++)
606 | {
607 | if (strcmp(argv[i], "-h")==0 || strcmp(argv[i],"--help")==0)
608 | help();
609 | else if (strcmp(argv[i], "-s")==0)
610 | {
611 | toshow |= eSummary;
612 | }
613 | else if (strcmp(argv[i], "-c")==0)
614 | {
615 | toshow |= eCounters;
616 | }
617 | else if (strcmp(argv[i], "-r")==0)
618 | {
619 | toshow |= eRows;
620 | }
621 | else if (strcmp(argv[i], "-v")==0)
622 | {
623 | toshow |= eVars;
624 | }
625 | else if (strcmp(argv[i], "-a")==0)
626 | {
627 | toshow |= ~eSummary;
628 | }
629 | else if (strcmp(argv[i], "-F")==0)
630 | {
631 | if (++i >= argc) die("missing argument to -F", NULL);
632 | g_delim = argv[i];
633 | g_showdelim = 1;
634 | }
635 | else if (strcmp(argv[i], "-z")==0)
636 | {
637 | g_showdelim = 0;
638 | }
639 | else if (strcmp(argv[i], "-t")==0)
640 | {
641 | g_terse = 1;
642 | }
643 | else if (strcmp(argv[i], "--version")==0)
644 | {
645 | printf("log2mem version: " PACKAGE_VERSION "\n");
646 | exit(1);
647 | }
648 | else if (strncmp(argv[i], OPT_DOUBLE, strlen(OPT_DOUBLE))==0)
649 | {
650 | set_var_double(argc, argv, &i, handle);
651 | defaultshow = 0;
652 | }
653 | else if (strncmp(argv[i], OPT_INT, strlen(OPT_INT))==0)
654 | {
655 | set_var_int(argc, argv, &i, handle);
656 | defaultshow = 0;
657 | }
658 | else if (strncmp(argv[i], OPT_STRING, strlen(OPT_STRING))==0)
659 | {
660 | set_var_string(argc, argv, &i, handle);
661 | defaultshow = 0;
662 | }
663 | else if ((strncmp(argv[i], "--",2)==0) && strlen(argv[i])>2 )
664 | {
665 | set_var_by_name(argc, argv, &i, handle);
666 | defaultshow = 0;
667 | }
668 | else
669 | {
670 | if (filename == 0)
671 | filename = argv[i];
672 | else
673 | {
674 | die("unexpected argument: ", argv[i]);
675 | }
676 | }
677 | }
678 |
679 | if (defaultshow && !toshow) toshow = 0xFFFF;
680 |
681 | if (!parseonly)
682 | {
683 | if (toshow & eSummary) print_summary(handle);
684 | if (toshow & eRows) print_rows(handle);
685 | if (toshow & eCounters) print_counters(handle);
686 | if (toshow & eVars) print_vars(handle);
687 | }
688 |
689 | return filename;
690 | }
691 | //----------------------------------------------------------------------
692 | int main(int argc, const char** argv)
693 | {
694 |
695 | struct log2mem_handle * handle = 0;
696 |
697 | const char* filename = parse_args(argc, argv, 1, handle);
698 |
699 | if (filename == 0) die("please specify filename of log2mem memmap", 0);
700 |
701 | handle = log2mem_attach(filename);
702 | if (!handle)
703 | {
704 | printf("failed to attach to memmap file '%s', error: %s\n", filename,
705 | log2mem_strerr());
706 | return 1;
707 | }
708 |
709 | parse_args(argc, argv, 0, handle);
710 |
711 | return 0;
712 | }
713 |
--------------------------------------------------------------------------------