├── .gitignore
├── README.md
├── SConstruct
├── book
├── SConscript
├── app
│ ├── ex6.md
│ ├── ex7.md
│ ├── interp.md
│ ├── java.md
│ ├── libc.md
│ ├── proc.md
│ └── web.md
├── bootstrap
│ ├── LICENSE
│ ├── img
│ │ ├── glyphicons-halflings-white.png
│ │ └── glyphicons-halflings.png
│ ├── js
│ │ ├── .jshintrc
│ │ ├── bootstrap-affix.js
│ │ ├── bootstrap-alert.js
│ │ ├── bootstrap-button.js
│ │ ├── bootstrap-carousel.js
│ │ ├── bootstrap-collapse.js
│ │ ├── bootstrap-dropdown.js
│ │ ├── bootstrap-modal.js
│ │ ├── bootstrap-popover.js
│ │ ├── bootstrap-scrollspy.js
│ │ ├── bootstrap-tab.js
│ │ ├── bootstrap-tooltip.js
│ │ ├── bootstrap-transition.js
│ │ ├── bootstrap-typeahead.js
│ │ └── tests
│ │ │ ├── index.html
│ │ │ ├── phantom.js
│ │ │ ├── server.js
│ │ │ ├── unit
│ │ │ ├── bootstrap-affix.js
│ │ │ ├── bootstrap-alert.js
│ │ │ ├── bootstrap-button.js
│ │ │ ├── bootstrap-carousel.js
│ │ │ ├── bootstrap-collapse.js
│ │ │ ├── bootstrap-dropdown.js
│ │ │ ├── bootstrap-modal.js
│ │ │ ├── bootstrap-phantom.js
│ │ │ ├── bootstrap-popover.js
│ │ │ ├── bootstrap-scrollspy.js
│ │ │ ├── bootstrap-tab.js
│ │ │ ├── bootstrap-tooltip.js
│ │ │ ├── bootstrap-transition.js
│ │ │ └── bootstrap-typeahead.js
│ │ │ └── vendor
│ │ │ ├── jquery.js
│ │ │ ├── qunit.css
│ │ │ └── qunit.js
│ └── less
│ │ ├── accordion.less
│ │ ├── alerts.less
│ │ ├── bootstrap.less
│ │ ├── breadcrumbs.less
│ │ ├── button-groups.less
│ │ ├── buttons.less
│ │ ├── carousel.less
│ │ ├── close.less
│ │ ├── code.less
│ │ ├── component-animations.less
│ │ ├── dropdowns.less
│ │ ├── forms.less
│ │ ├── grid.less
│ │ ├── hero-unit.less
│ │ ├── labels-badges.less
│ │ ├── layouts.less
│ │ ├── media.less
│ │ ├── mixins.less
│ │ ├── modals.less
│ │ ├── navbar.less
│ │ ├── navs.less
│ │ ├── pager.less
│ │ ├── pagination.less
│ │ ├── popovers.less
│ │ ├── progress-bars.less
│ │ ├── reset.less
│ │ ├── responsive-1200px-min.less
│ │ ├── responsive-767px-max.less
│ │ ├── responsive-768px-979px.less
│ │ ├── responsive-navbar.less
│ │ ├── responsive-utilities.less
│ │ ├── responsive.less
│ │ ├── scaffolding.less
│ │ ├── sprites.less
│ │ ├── tables.less
│ │ ├── thumbnails.less
│ │ ├── tooltip.less
│ │ ├── type.less
│ │ ├── utilities.less
│ │ ├── variables.less
│ │ └── wells.less
├── cheatsheet
│ └── cheatsheet.md
├── epub.css
├── hints
│ ├── ex1.md
│ ├── ex2.md
│ ├── ex3.md
│ ├── ex4.md
│ ├── ex5.md
│ ├── ex6.md
│ └── ex7.md
├── index.md
├── intro
│ ├── conv.md
│ ├── experiment.json
│ ├── foreword.md
│ ├── oskernel.md
│ └── tsload.md
├── kernel
│ ├── async.md
│ ├── bio.md
│ ├── ex3.md
│ ├── ex4.md
│ ├── ex5.md
│ ├── fs.md
│ ├── irq.md
│ ├── net.md
│ ├── proc.md
│ ├── sched.md
│ ├── sobj.md
│ └── virtmem.md
├── lab
│ ├── iscsi.md
│ ├── os.md
│ └── web.md
├── lang
│ ├── args.md
│ ├── assocarr.md
│ ├── context.md
│ ├── ex1.md
│ ├── ex2.md
│ ├── intro.md
│ ├── pointers.md
│ ├── predicates.md
│ ├── print.md
│ ├── probes.md
│ ├── strstr.md
│ ├── tapset.md
│ ├── time.md
│ └── vars.md
├── principles
│ ├── apply.md
│ ├── dyncode.md
│ ├── perf.md
│ ├── prepost.md
│ ├── profiling.md
│ └── viz.md
├── template.html
├── tools
│ ├── dtrace.md
│ ├── dyntrace.md
│ ├── safety.md
│ ├── stability.md
│ ├── systemtap.md
│ └── tracing.md
└── watermark.txt
├── experiments
├── concurrency
│ └── experiment.json
├── deblock
│ └── experiment.json
├── drupal
│ └── experiment.json
├── duality
│ └── experiment.json
├── pthread
│ └── experiment.json
└── readahead
│ └── experiment.json
├── fonts
├── DejaVuSansMono-Bold.ttf
├── DejaVuSansMono-BoldOblique.ttf
├── DejaVuSansMono-Oblique.ttf
├── DejaVuSansMono.ttf
├── lcmss8.afm
└── lcmss8.pfb
├── images
├── SConscript
├── aggrs.svg
├── aio.svg
├── appprobes.svg
├── bio.svg
├── catfiles.svg
├── conv
│ ├── array.svg
│ ├── embed.svg
│ ├── list.svg
│ ├── pointer.svg
│ └── reverse.svg
├── cpubufs.svg
├── density.png
├── dtrace.svg
├── dyntrace.svg
├── forkproc.svg
├── heatmap.png
├── icons
│ ├── book.svg
│ ├── dtrace.svg
│ ├── manpage.svg
│ ├── staplang.svg
│ └── stapset.svg
├── java.svg
├── kmem.svg
├── linear.png
├── linux
│ ├── bio.svg
│ ├── mm.svg
│ ├── net.svg
│ ├── sched.svg
│ ├── task.svg
│ └── vfs.svg
├── localglobal.svg
├── merge-svgs.py
├── net.svg
├── netprobes.svg
├── oncpu.png
├── pagetable.svg
├── pas.svg
├── perf.svg
├── pointers.svg
├── prepost.svg
├── probes.svg
├── ringbuf-proto.svg
├── ringbuf.svg
├── sched.svg
├── sobj.svg
├── solaris
│ ├── as.svg
│ ├── bio.svg
│ ├── net.svg
│ ├── proc.svg
│ ├── sched.svg
│ ├── streams.svg
│ └── vfs.svg
├── stackfmt.svg
├── stapprocess.svg
├── timeline.svg
├── timer-probe.svg
├── tsload.svg
├── varscope.svg
├── vfsops.svg
└── webapp.svg
├── scripts
├── dtrace
│ ├── callgraph.d
│ ├── cvtrace.d
│ ├── deblock.d
│ ├── dumptask-lab3.d
│ ├── dumptask.d
│ ├── forktime.d
│ ├── hotspot.d
│ ├── kmemstat.d
│ ├── mtxtime.d
│ ├── openaggr.d
│ ├── opentrace.d
│ ├── pagefault.d
│ ├── pfstat.d
│ ├── proc.d
│ ├── pthread.d
│ ├── pycode.d
│ ├── pycode.h
│ ├── pymalloc.d
│ ├── readahead.d
│ ├── sdtrace.d
│ ├── stat.d
│ ├── topphp.d
│ ├── tstrace.d
│ ├── web.d
│ └── wstat.d
├── src
│ ├── hellouser.py
│ ├── java
│ │ ├── Greeter.java
│ │ ├── Greeting.java
│ │ └── GreetingThread.java
│ ├── jsdt
│ │ ├── Greeting.java
│ │ ├── GreetingProvider.java
│ │ └── JSDT.java
│ ├── lab3.c
│ ├── openproc.py
│ ├── opentrace.py
│ └── pthread.c
└── stap
│ ├── callgraph.stp
│ ├── cfstrace.stp
│ ├── deblock.stp
│ ├── dumptask-lab3.stp
│ ├── dumptask.stp
│ ├── forktime.stp
│ ├── hotspot.stp
│ ├── kmemstat.stp
│ ├── lstat.stp
│ ├── mtxtime.stp
│ ├── openaggr.stp
│ ├── opentrace.stp
│ ├── pagefault.stp
│ ├── pfstat.stp
│ ├── proc.stp
│ ├── pthread.stp
│ ├── pycode.stp
│ ├── pymalloc.stp
│ ├── readahead.stp
│ ├── scsitrace.stp
│ ├── tapset
│ └── lstat.stp
│ ├── topphp.stp
│ ├── web.stp
│ ├── wqtrace.stp
│ └── wstat.stp
├── tsdoc
├── gen-cheatsheet.py
├── gen-doc.py
└── tsdoc
│ ├── __init__.py
│ ├── blocks
│ ├── __init__.py
│ ├── epub.py
│ ├── html.py
│ ├── latex.py
│ ├── markdown.py
│ └── pdf.py
│ ├── mdparser2.py
│ └── page.py
└── tsload
├── SConstruct
├── file_opener
├── .ctime_cache
├── SConscript
├── experiment.json
├── file_opener.c
├── include
│ └── file_opener.h
└── modinfo.cfg
└── proc_starter
├── .ctime_cache
├── SConscript
├── experiment.json
├── include
├── proc_starter.h
└── shell.h
├── modinfo.json
├── proc_starter.c
└── shell.c
/.gitignore:
--------------------------------------------------------------------------------
1 | .kdev4
2 | *.kdev4
3 | .sconsign.dblite
4 | build/
5 | *.pyc
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dtrace-stap-book
2 |
3 | This repository contains source code for book "Dynamic Tracing with DTrace & SystemTap", example scripts and TSLoad modules used in exercises. It is written on extended version of Markdown (which is implemented by TSDoc subsystem) and uses SCons for building. The only supported backend for building book is HTML.
4 |
5 | ### Contents
6 |
7 | This book describes basic principles and languages of dynamic tracing and operating system kernel internals and how they may be exposed with dynamic tracing. Last module of a book is devoted to tracing of userspace applications.
8 |
9 | There are 7 exercises in this book that allow you to try yourself in writing tracing scripts and observe mildly interesting aspects of computer systems.
10 |
11 | ### Errors and requests
12 |
13 | As I am non-native in English, I would appreciate help in editing. If you see ways to expand or improve book, do not hesitate to register an issue so I can consider putting it in further revisions of book.
14 |
15 | ### License
16 |
17 | This work is licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
18 |
--------------------------------------------------------------------------------
/SConstruct:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | env = DefaultEnvironment()
5 |
6 | AddOption('--doc-format', dest='doc_format', action="store", default='html',
7 | metavar='FORMAT', help='Documentation format (markdown or html)')
8 | AddOption('--verbose', dest='verbose', action='store_true', default=False,
9 | help='Be verbose')
10 | AddOption('--no-sources', dest='no_sources', action='store_true', default=False,
11 | help='Do not put source files to book')
12 |
13 | LessBuilder = Builder(action = Action('lesscpy $LESSFLAGS $SOURCE > $TARGET'),
14 | suffix = '.css',
15 | src_suffix = '.less')
16 | env.Append(BUILDERS = {'LessBuilder': LessBuilder})
17 |
18 | VariantDir('build/book/images', 'images')
19 | SConscript('build/book/images/SConscript', 'env')
20 |
21 | VariantDir('build/book', 'book')
22 | SConscript('build/book/SConscript', 'env')
--------------------------------------------------------------------------------
/book/SConscript:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from SCons.Errors import StopError
4 |
5 | Import('env')
6 |
7 | def GlobDocs(doc_dir):
8 | return Dir(doc_dir).glob('*.md')
9 |
10 | doc_format = GetOption('doc_format')
11 | if doc_format == 'html':
12 | doc_suffix = '.html'
13 | elif doc_format == 'markdown':
14 | doc_suffix = '.md'
15 | elif doc_format == 'latex':
16 | doc_suffix = '.tex'
17 | elif doc_format == 'pdf':
18 | doc_suffix = '.pdf'
19 | elif doc_format == 'epub':
20 | doc_suffix = '.epub'
21 | else:
22 | raise StopError("Invalid documentation format '%s'" % doc_format)
23 |
24 | DocGenerator = Builder(action = Action('%s tsdoc/gen-doc.py $SOURCES' % (sys.executable)),
25 | src_suffix = '.md', suffix = doc_suffix)
26 | CheatsheetGenerator = Builder(action = Action('%s tsdoc/gen-cheatsheet.py $SOURCE $TARGET' % (sys.executable)),
27 | src_suffix = '.md', suffix = '.pdf')
28 |
29 | env.Append(BUILDERS = {'DocGenerator': DocGenerator,
30 | 'CheatsheetGenerator': CheatsheetGenerator})
31 |
32 | env.Append(ENV = {'TSDOC_FORMAT': doc_format})
33 | env.Append(ENV = {'TSDOC_HEADER': 'Dynamic Tracing with DTrace & SystemTap'})
34 | env.Append(ENV = {'TSDOC_AUTHOR': 'Sergey Klyaus'})
35 | env.Append(ENV = {'TSDOC_UID': 'dtrace_stap_book'})
36 | env.Append(ENV = {'TSDOC_IMGDIR': 'build/book/images'})
37 | env.Append(ENV = {'TSDOC_HTML_TEMPLATE': File('template.html').abspath})
38 | if GetOption('verbose'):
39 | env.Append(ENV = {'TSDOC_VERBOSE': True})
40 | if GetOption('no_sources'):
41 | env.Append(ENV = {'TSDOC_NO_SOURCES': True})
42 |
43 |
44 | index = File('index.md')
45 |
46 | if doc_format == 'html':
47 | cssdir, lessdir = Dir('bootstrap').Dir('css'), Dir('bootstrap').Dir('less')
48 |
49 | for lessname, cssname in [('bootstrap.less', 'bootstrap.css'),
50 | ('responsive.less', 'bootstrap-responsive.css')]:
51 | bsless = lessdir.File(lessname)
52 | bscss = cssdir.File(cssname)
53 |
54 | # Implicit dependencies
55 | for less in lessdir.glob('*.less'):
56 | env.Depends(bscss, less)
57 |
58 | # Build bootstrap from less
59 | env.LessBuilder(bscss, bsless)
60 | env.Depends(index, bscss)
61 |
62 | docs = env.DocGenerator([index] + GlobDocs('intro') + GlobDocs('tools')
63 | + GlobDocs('lang') + GlobDocs('principles')
64 | + GlobDocs('kernel') + GlobDocs('app')
65 | + GlobDocs('hints') + GlobDocs('lab')
66 | + GlobDocs('cheatsheet'))
67 | env.Depends(docs, 'template.html')
68 | env.Depends(docs, 'images')
69 | env.AlwaysBuild(docs)
70 |
71 | csenv = env.Clone()
72 | csenv.Append(ENV = {'TSDOC_HEADER': 'DTrace & SystemTap cheatsheet'})
73 | cs = csenv.CheatsheetGenerator('cheatsheet.pdf', 'cheatsheet/cheatsheet.md')
74 |
--------------------------------------------------------------------------------
/book/app/ex6.md:
--------------------------------------------------------------------------------
1 | ### Exercise 6
2 |
3 | Implement two scripts: `mtxtime.d` and `mtxtimd.stp` that would compute delay between attempt to acquire a userspace mutex and a moment when mutex is acquired. Group times by user stacks and print data as logarithmic histograms.
4 |
5 | Use `pthread` experiment to demonstrate your scripts, like in previous section, TSLoad workload generator itself would be an object in the experiment. Try to identify mutexes that show delays larger than 1 ms.
6 |
7 | !!! WARN
8 | To prevent problems with symbol resolving in DTrace after tracing process finishes, you can attach to a function `experiment_unconfigure()` from `tsexperiment` to print gathered data.
9 | !!!
--------------------------------------------------------------------------------
/book/app/ex7.md:
--------------------------------------------------------------------------------
1 | ### Exercise 7
2 |
3 | Create two scripts: `topphp.d` and `topphp.stp` which will measure mean execution time of each PHP function and count number of calls to that function. Group functions by request URI and full function name including class name (if defined). Use `drupal` experiment to demonstrate your script.
4 |
5 | !!! NOTE
6 | It would be reasonable to run workload generator on system other than server (so it won't affect execution of web applications). You can switch roles of virtual machines in lab environment i.e. use Solaris as server and Linux as client and vice versa. To alter server's address, use `-s` option in `tsexperiment` command line:
7 | ```
8 | # /opt/tsload/bin/tsexperiment -e drupal/ run \
9 | -s workloads:drupal:params:server=192.168.13.102
10 | ```
11 | !!!
12 |
--------------------------------------------------------------------------------
/book/bootstrap/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/book/bootstrap/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/book/bootstrap/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/book/bootstrap/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/book/bootstrap/js/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "validthis": true,
3 | "laxcomma" : true,
4 | "laxbreak" : true,
5 | "browser" : true,
6 | "eqnull" : true,
7 | "debug" : true,
8 | "devel" : true,
9 | "boss" : true,
10 | "expr" : true,
11 | "asi" : true
12 | }
--------------------------------------------------------------------------------
/book/bootstrap/js/bootstrap-alert.js:
--------------------------------------------------------------------------------
1 | /* ==========================================================
2 | * bootstrap-alert.js v2.3.2
3 | * http://getbootstrap.com/2.3.2/javascript.html#alerts
4 | * ==========================================================
5 | * Copyright 2013 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* ALERT CLASS DEFINITION
27 | * ====================== */
28 |
29 | var dismiss = '[data-dismiss="alert"]'
30 | , Alert = function (el) {
31 | $(el).on('click', dismiss, this.close)
32 | }
33 |
34 | Alert.prototype.close = function (e) {
35 | var $this = $(this)
36 | , selector = $this.attr('data-target')
37 | , $parent
38 |
39 | if (!selector) {
40 | selector = $this.attr('href')
41 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
42 | }
43 |
44 | $parent = $(selector)
45 |
46 | e && e.preventDefault()
47 |
48 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
49 |
50 | $parent.trigger(e = $.Event('close'))
51 |
52 | if (e.isDefaultPrevented()) return
53 |
54 | $parent.removeClass('in')
55 |
56 | function removeElement() {
57 | $parent
58 | .trigger('closed')
59 | .remove()
60 | }
61 |
62 | $.support.transition && $parent.hasClass('fade') ?
63 | $parent.on($.support.transition.end, removeElement) :
64 | removeElement()
65 | }
66 |
67 |
68 | /* ALERT PLUGIN DEFINITION
69 | * ======================= */
70 |
71 | var old = $.fn.alert
72 |
73 | $.fn.alert = function (option) {
74 | return this.each(function () {
75 | var $this = $(this)
76 | , data = $this.data('alert')
77 | if (!data) $this.data('alert', (data = new Alert(this)))
78 | if (typeof option == 'string') data[option].call($this)
79 | })
80 | }
81 |
82 | $.fn.alert.Constructor = Alert
83 |
84 |
85 | /* ALERT NO CONFLICT
86 | * ================= */
87 |
88 | $.fn.alert.noConflict = function () {
89 | $.fn.alert = old
90 | return this
91 | }
92 |
93 |
94 | /* ALERT DATA-API
95 | * ============== */
96 |
97 | $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
98 |
99 | }(window.jQuery);
--------------------------------------------------------------------------------
/book/bootstrap/js/bootstrap-button.js:
--------------------------------------------------------------------------------
1 | /* ============================================================
2 | * bootstrap-button.js v2.3.2
3 | * http://getbootstrap.com/2.3.2/javascript.html#buttons
4 | * ============================================================
5 | * Copyright 2013 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ============================================================ */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* BUTTON PUBLIC CLASS DEFINITION
27 | * ============================== */
28 |
29 | var Button = function (element, options) {
30 | this.$element = $(element)
31 | this.options = $.extend({}, $.fn.button.defaults, options)
32 | }
33 |
34 | Button.prototype.setState = function (state) {
35 | var d = 'disabled'
36 | , $el = this.$element
37 | , data = $el.data()
38 | , val = $el.is('input') ? 'val' : 'html'
39 |
40 | state = state + 'Text'
41 | data.resetText || $el.data('resetText', $el[val]())
42 |
43 | $el[val](data[state] || this.options[state])
44 |
45 | // push to event loop to allow forms to submit
46 | setTimeout(function () {
47 | state == 'loadingText' ?
48 | $el.addClass(d).attr(d, d) :
49 | $el.removeClass(d).removeAttr(d)
50 | }, 0)
51 | }
52 |
53 | Button.prototype.toggle = function () {
54 | var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
55 |
56 | $parent && $parent
57 | .find('.active')
58 | .removeClass('active')
59 |
60 | this.$element.toggleClass('active')
61 | }
62 |
63 |
64 | /* BUTTON PLUGIN DEFINITION
65 | * ======================== */
66 |
67 | var old = $.fn.button
68 |
69 | $.fn.button = function (option) {
70 | return this.each(function () {
71 | var $this = $(this)
72 | , data = $this.data('button')
73 | , options = typeof option == 'object' && option
74 | if (!data) $this.data('button', (data = new Button(this, options)))
75 | if (option == 'toggle') data.toggle()
76 | else if (option) data.setState(option)
77 | })
78 | }
79 |
80 | $.fn.button.defaults = {
81 | loadingText: 'loading...'
82 | }
83 |
84 | $.fn.button.Constructor = Button
85 |
86 |
87 | /* BUTTON NO CONFLICT
88 | * ================== */
89 |
90 | $.fn.button.noConflict = function () {
91 | $.fn.button = old
92 | return this
93 | }
94 |
95 |
96 | /* BUTTON DATA-API
97 | * =============== */
98 |
99 | $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
100 | var $btn = $(e.target)
101 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
102 | $btn.button('toggle')
103 | })
104 |
105 | }(window.jQuery);
--------------------------------------------------------------------------------
/book/bootstrap/js/bootstrap-popover.js:
--------------------------------------------------------------------------------
1 | /* ===========================================================
2 | * bootstrap-popover.js v2.3.2
3 | * http://getbootstrap.com/2.3.2/javascript.html#popovers
4 | * ===========================================================
5 | * Copyright 2013 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * =========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* POPOVER PUBLIC CLASS DEFINITION
27 | * =============================== */
28 |
29 | var Popover = function (element, options) {
30 | this.init('popover', element, options)
31 | }
32 |
33 |
34 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
35 | ========================================== */
36 |
37 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
38 |
39 | constructor: Popover
40 |
41 | , setContent: function () {
42 | var $tip = this.tip()
43 | , title = this.getTitle()
44 | , content = this.getContent()
45 |
46 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
47 | $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
48 |
49 | $tip.removeClass('fade top bottom left right in')
50 | }
51 |
52 | , hasContent: function () {
53 | return this.getTitle() || this.getContent()
54 | }
55 |
56 | , getContent: function () {
57 | var content
58 | , $e = this.$element
59 | , o = this.options
60 |
61 | content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
62 | || $e.attr('data-content')
63 |
64 | return content
65 | }
66 |
67 | , tip: function () {
68 | if (!this.$tip) {
69 | this.$tip = $(this.options.template)
70 | }
71 | return this.$tip
72 | }
73 |
74 | , destroy: function () {
75 | this.hide().$element.off('.' + this.type).removeData(this.type)
76 | }
77 |
78 | })
79 |
80 |
81 | /* POPOVER PLUGIN DEFINITION
82 | * ======================= */
83 |
84 | var old = $.fn.popover
85 |
86 | $.fn.popover = function (option) {
87 | return this.each(function () {
88 | var $this = $(this)
89 | , data = $this.data('popover')
90 | , options = typeof option == 'object' && option
91 | if (!data) $this.data('popover', (data = new Popover(this, options)))
92 | if (typeof option == 'string') data[option]()
93 | })
94 | }
95 |
96 | $.fn.popover.Constructor = Popover
97 |
98 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
99 | placement: 'right'
100 | , trigger: 'click'
101 | , content: ''
102 | , template: '
'
103 | })
104 |
105 |
106 | /* POPOVER NO CONFLICT
107 | * =================== */
108 |
109 | $.fn.popover.noConflict = function () {
110 | $.fn.popover = old
111 | return this
112 | }
113 |
114 | }(window.jQuery);
115 |
--------------------------------------------------------------------------------
/book/bootstrap/js/bootstrap-transition.js:
--------------------------------------------------------------------------------
1 | /* ===================================================
2 | * bootstrap-transition.js v2.3.2
3 | * http://getbootstrap.com/2.3.2/javascript.html#transitions
4 | * ===================================================
5 | * Copyright 2013 Twitter, Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | * ========================================================== */
19 |
20 |
21 | !function ($) {
22 |
23 | "use strict"; // jshint ;_;
24 |
25 |
26 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27 | * ======================================================= */
28 |
29 | $(function () {
30 |
31 | $.support.transition = (function () {
32 |
33 | var transitionEnd = (function () {
34 |
35 | var el = document.createElement('bootstrap')
36 | , transEndEventNames = {
37 | 'WebkitTransition' : 'webkitTransitionEnd'
38 | , 'MozTransition' : 'transitionend'
39 | , 'OTransition' : 'oTransitionEnd otransitionend'
40 | , 'transition' : 'transitionend'
41 | }
42 | , name
43 |
44 | for (name in transEndEventNames){
45 | if (el.style[name] !== undefined) {
46 | return transEndEventNames[name]
47 | }
48 | }
49 |
50 | }())
51 |
52 | return transitionEnd && {
53 | end: transitionEnd
54 | }
55 |
56 | })()
57 |
58 | })
59 |
60 | }(window.jQuery);
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Bootstrap Plugin Test Suite
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/phantom.js:
--------------------------------------------------------------------------------
1 | // Simple phantom.js integration script
2 | // Adapted from Modernizr
3 |
4 | function waitFor(testFx, onReady, timeOutMillis) {
5 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 5001 //< Default Max Timout is 5s
6 | , start = new Date().getTime()
7 | , condition = false
8 | , interval = setInterval(function () {
9 | if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
10 | // If not time-out yet and condition not yet fulfilled
11 | condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()) //< defensive code
12 | } else {
13 | if (!condition) {
14 | // If condition still not fulfilled (timeout but condition is 'false')
15 | console.log("'waitFor()' timeout")
16 | phantom.exit(1)
17 | } else {
18 | // Condition fulfilled (timeout and/or condition is 'true')
19 | typeof(onReady) === "string" ? eval(onReady) : onReady() //< Do what it's supposed to do once the condition is fulfilled
20 | clearInterval(interval) //< Stop this interval
21 | }
22 | }
23 | }, 100) //< repeat check every 100ms
24 | }
25 |
26 |
27 | if (phantom.args.length === 0 || phantom.args.length > 2) {
28 | console.log('Usage: phantom.js URL')
29 | phantom.exit()
30 | }
31 |
32 | var page = new WebPage()
33 |
34 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
35 | page.onConsoleMessage = function(msg) {
36 | console.log(msg)
37 | };
38 |
39 | page.open(phantom.args[0], function(status){
40 | if (status !== "success") {
41 | console.log("Unable to access network")
42 | phantom.exit()
43 | } else {
44 | waitFor(function(){
45 | return page.evaluate(function(){
46 | var el = document.getElementById('qunit-testresult')
47 | if (el && el.innerText.match('completed')) {
48 | return true
49 | }
50 | return false
51 | })
52 | }, function(){
53 | var failedNum = page.evaluate(function(){
54 | var el = document.getElementById('qunit-testresult')
55 | try {
56 | return el.getElementsByClassName('failed')[0].innerHTML
57 | } catch (e) { }
58 | return 10000
59 | });
60 | phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0)
61 | })
62 | }
63 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/server.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple connect server for phantom.js
3 | * Adapted from Modernizr
4 | */
5 |
6 | var connect = require('connect')
7 | , http = require('http')
8 | , fs = require('fs')
9 | , app = connect()
10 | .use(connect.static(__dirname + '/../../'));
11 |
12 | http.createServer(app).listen(3000);
13 |
14 | fs.writeFileSync(__dirname + '/pid.txt', process.pid, 'utf-8')
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-affix.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-affix")
4 |
5 | test("should provide no conflict", function () {
6 | var affix = $.fn.affix.noConflict()
7 | ok(!$.fn.affix, 'affix was set back to undefined (org value)')
8 | $.fn.affix = affix
9 | })
10 |
11 | test("should be defined on jquery object", function () {
12 | ok($(document.body).affix, 'affix method is defined')
13 | })
14 |
15 | test("should return element", function () {
16 | ok($(document.body).affix()[0] == document.body, 'document.body returned')
17 | })
18 |
19 | test("should exit early if element is not visible", function () {
20 | var $affix = $('').affix()
21 | $affix.data('affix').checkPosition()
22 | ok(!$affix.hasClass('affix'), 'affix class was not added')
23 | })
24 |
25 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-alert.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-alerts")
4 |
5 | test("should provide no conflict", function () {
6 | var alert = $.fn.alert.noConflict()
7 | ok(!$.fn.alert, 'alert was set back to undefined (org value)')
8 | $.fn.alert = alert
9 | })
10 |
11 | test("should be defined on jquery object", function () {
12 | ok($(document.body).alert, 'alert method is defined')
13 | })
14 |
15 | test("should return element", function () {
16 | ok($(document.body).alert()[0] == document.body, 'document.body returned')
17 | })
18 |
19 | test("should fade element out on clicking .close", function () {
20 | var alertHTML = ''
21 | + '
×'
22 | + '
Holy guacamole! Best check yo self, you\'re not looking too good.
'
23 | + '
'
24 | , alert = $(alertHTML).alert()
25 |
26 | alert.find('.close').click()
27 |
28 | ok(!alert.hasClass('in'), 'remove .in class on .close click')
29 | })
30 |
31 | test("should remove element when clicking .close", function () {
32 | $.support.transition = false
33 |
34 | var alertHTML = ''
35 | + '
×'
36 | + '
Holy guacamole! Best check yo self, you\'re not looking too good.
'
37 | + '
'
38 | , alert = $(alertHTML).appendTo('#qunit-fixture').alert()
39 |
40 | ok($('#qunit-fixture').find('.alert-message').length, 'element added to dom')
41 |
42 | alert.find('.close').click()
43 |
44 | ok(!$('#qunit-fixture').find('.alert-message').length, 'element removed from dom')
45 | })
46 |
47 | test("should not fire closed when close is prevented", function () {
48 | $.support.transition = false
49 | stop();
50 | $('')
51 | .bind('close', function (e) {
52 | e.preventDefault();
53 | ok(true);
54 | start();
55 | })
56 | .bind('closed', function () {
57 | ok(false);
58 | })
59 | .alert('close')
60 | })
61 |
62 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-collapse.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-collapse")
4 |
5 | test("should provide no conflict", function () {
6 | var collapse = $.fn.collapse.noConflict()
7 | ok(!$.fn.collapse, 'collapse was set back to undefined (org value)')
8 | $.fn.collapse = collapse
9 | })
10 |
11 | test("should be defined on jquery object", function () {
12 | ok($(document.body).collapse, 'collapse method is defined')
13 | })
14 |
15 | test("should return element", function () {
16 | ok($(document.body).collapse()[0] == document.body, 'document.body returned')
17 | })
18 |
19 | test("should show a collapsed element", function () {
20 | var el = $('').collapse('show')
21 | ok(el.hasClass('in'), 'has class in')
22 | ok(/height/.test(el.attr('style')), 'has height set')
23 | })
24 |
25 | test("should hide a collapsed element", function () {
26 | var el = $('').collapse('hide')
27 | ok(!el.hasClass('in'), 'does not have class in')
28 | ok(/height/.test(el.attr('style')), 'has height set')
29 | })
30 |
31 | test("should not fire shown when show is prevented", function () {
32 | $.support.transition = false
33 | stop()
34 | $('')
35 | .bind('show', function (e) {
36 | e.preventDefault();
37 | ok(true);
38 | start();
39 | })
40 | .bind('shown', function () {
41 | ok(false);
42 | })
43 | .collapse('show')
44 | })
45 |
46 | test("should reset style to auto after finishing opening collapse", function () {
47 | $.support.transition = false
48 | stop()
49 | $('')
50 | .bind('show', function () {
51 | ok(this.style.height == '0px')
52 | })
53 | .bind('shown', function () {
54 | ok(this.style.height == 'auto')
55 | start()
56 | })
57 | .collapse('show')
58 | })
59 |
60 | test("should add active class to target when collapse shown", function () {
61 | $.support.transition = false
62 | stop()
63 |
64 | var target = $('')
65 | .appendTo($('#qunit-fixture'))
66 |
67 | var collapsible = $('')
68 | .appendTo($('#qunit-fixture'))
69 | .on('show', function () {
70 | ok(!target.hasClass('collapsed'))
71 | start()
72 | })
73 |
74 | target.click()
75 | })
76 |
77 | test("should remove active class to target when collapse hidden", function () {
78 | $.support.transition = false
79 | stop()
80 |
81 | var target = $('')
82 | .appendTo($('#qunit-fixture'))
83 |
84 | var collapsible = $('')
85 | .appendTo($('#qunit-fixture'))
86 | .on('hide', function () {
87 | ok(target.hasClass('collapsed'))
88 | start()
89 | })
90 |
91 | target.click()
92 | })
93 |
94 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-phantom.js:
--------------------------------------------------------------------------------
1 | // Logging setup for phantom integration
2 | // adapted from Modernizr
3 |
4 | QUnit.begin = function () {
5 | console.log("Starting test suite")
6 | console.log("================================================\n")
7 | }
8 |
9 | QUnit.moduleDone = function (opts) {
10 | if (opts.failed === 0) {
11 | console.log("\u2714 All tests passed in '" + opts.name + "' module")
12 | } else {
13 | console.log("\u2716 " + opts.failed + " tests failed in '" + opts.name + "' module")
14 | }
15 | }
16 |
17 | QUnit.done = function (opts) {
18 | console.log("\n================================================")
19 | console.log("Tests completed in " + opts.runtime + " milliseconds")
20 | console.log(opts.passed + " tests of " + opts.total + " passed, " + opts.failed + " failed.")
21 | }
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-scrollspy.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-scrollspy")
4 |
5 | test("should provide no conflict", function () {
6 | var scrollspy = $.fn.scrollspy.noConflict()
7 | ok(!$.fn.scrollspy, 'scrollspy was set back to undefined (org value)')
8 | $.fn.scrollspy = scrollspy
9 | })
10 |
11 | test("should be defined on jquery object", function () {
12 | ok($(document.body).scrollspy, 'scrollspy method is defined')
13 | })
14 |
15 | test("should return element", function () {
16 | ok($(document.body).scrollspy()[0] == document.body, 'document.body returned')
17 | })
18 |
19 | test("should switch active class on scroll", function () {
20 | var sectionHTML = ''
21 | , $section = $(sectionHTML).append('#qunit-fixture')
22 | , topbarHTML =''
23 | + '
'
24 | + '
'
25 | + '
'
26 | + '
'
29 | + '
'
30 | + '
'
31 | + '
'
32 | , $topbar = $(topbarHTML).scrollspy()
33 |
34 | ok($topbar.find('.active', true))
35 | })
36 |
37 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-tab.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-tabs")
4 |
5 | test("should provide no conflict", function () {
6 | var tab = $.fn.tab.noConflict()
7 | ok(!$.fn.tab, 'tab was set back to undefined (org value)')
8 | $.fn.tab = tab
9 | })
10 |
11 | test("should be defined on jquery object", function () {
12 | ok($(document.body).tab, 'tabs method is defined')
13 | })
14 |
15 | test("should return element", function () {
16 | ok($(document.body).tab()[0] == document.body, 'document.body returned')
17 | })
18 |
19 | test("should activate element by tab id", function () {
20 | var tabsHTML =
21 | ''
25 |
26 | $('').appendTo("#qunit-fixture")
27 |
28 | $(tabsHTML).find('li:last a').tab('show')
29 | equals($("#qunit-fixture").find('.active').attr('id'), "profile")
30 |
31 | $(tabsHTML).find('li:first a').tab('show')
32 | equals($("#qunit-fixture").find('.active').attr('id'), "home")
33 | })
34 |
35 | test("should activate element by tab id", function () {
36 | var pillsHTML =
37 | ''
41 |
42 | $('').appendTo("#qunit-fixture")
43 |
44 | $(pillsHTML).find('li:last a').tab('show')
45 | equals($("#qunit-fixture").find('.active').attr('id'), "profile")
46 |
47 | $(pillsHTML).find('li:first a').tab('show')
48 | equals($("#qunit-fixture").find('.active').attr('id'), "home")
49 | })
50 |
51 |
52 | test("should not fire closed when close is prevented", function () {
53 | $.support.transition = false
54 | stop();
55 | $('')
56 | .bind('show', function (e) {
57 | e.preventDefault();
58 | ok(true);
59 | start();
60 | })
61 | .bind('shown', function () {
62 | ok(false);
63 | })
64 | .tab('show')
65 | })
66 |
67 | test("show and shown events should reference correct relatedTarget", function () {
68 | var dropHTML =
69 | ''
70 | + '- 1'
71 | + ''
75 | + '
'
76 | + '
'
77 |
78 | $(dropHTML).find('ul>li:first a').tab('show').end()
79 | .find('ul>li:last a').on('show', function(event){
80 | equals(event.relatedTarget.hash, "#1-1")
81 | }).on('shown', function(event){
82 | equals(event.relatedTarget.hash, "#1-1")
83 | }).tab('show')
84 | })
85 |
86 | })
--------------------------------------------------------------------------------
/book/bootstrap/js/tests/unit/bootstrap-transition.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | module("bootstrap-transition")
4 |
5 | test("should be defined on jquery support object", function () {
6 | ok($.support.transition !== undefined, 'transition object is defined')
7 | })
8 |
9 | test("should provide an end object", function () {
10 | ok($.support.transition ? $.support.transition.end : true, 'end string is defined')
11 | })
12 |
13 | })
--------------------------------------------------------------------------------
/book/bootstrap/less/accordion.less:
--------------------------------------------------------------------------------
1 | //
2 | // Accordion
3 | // --------------------------------------------------
4 |
5 |
6 | // Parent container
7 | .accordion {
8 | margin-bottom: @baseLineHeight;
9 | }
10 |
11 | // Group == heading + body
12 | .accordion-group {
13 | margin-bottom: 2px;
14 | border: 1px solid #e5e5e5;
15 | .border-radius(@baseBorderRadius);
16 | }
17 | .accordion-heading {
18 | border-bottom: 0;
19 | }
20 | .accordion-heading .accordion-toggle {
21 | display: block;
22 | padding: 8px 15px;
23 | }
24 |
25 | // General toggle styles
26 | .accordion-toggle {
27 | cursor: pointer;
28 | }
29 |
30 | // Inner needs the styles because you can't animate properly with any styles on the element
31 | .accordion-inner {
32 | padding: 9px 15px;
33 | border-top: 1px solid #e5e5e5;
34 | }
35 |
--------------------------------------------------------------------------------
/book/bootstrap/less/alerts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Alerts
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // -------------------------
8 |
9 | .alert {
10 | padding: 8px 35px 8px 14px;
11 | margin-bottom: @baseLineHeight;
12 | text-shadow: 0 1px 0 rgba(255,255,255,.5);
13 | background-color: @warningBackground;
14 | border: 1px solid @warningBorder;
15 | .border-radius(@baseBorderRadius);
16 | }
17 | .alert,
18 | .alert h4 {
19 | // Specified for the h4 to prevent conflicts of changing @headingsColor
20 | color: @warningText;
21 | }
22 | .alert h4 {
23 | margin: 0;
24 | }
25 |
26 | // Adjust close link position
27 | .alert .close {
28 | position: relative;
29 | top: -2px;
30 | right: -21px;
31 | line-height: @baseLineHeight;
32 | }
33 |
34 |
35 | // Alternate styles
36 | // -------------------------
37 |
38 | .alert-success {
39 | background-color: @successBackground;
40 | border-color: @successBorder;
41 | color: @successText;
42 | }
43 | .alert-success h4 {
44 | color: @successText;
45 | }
46 | .alert-danger,
47 | .alert-error {
48 | background-color: @errorBackground;
49 | border-color: @errorBorder;
50 | color: @errorText;
51 | }
52 | .alert-danger h4,
53 | .alert-error h4 {
54 | color: @errorText;
55 | }
56 | .alert-info {
57 | background-color: @infoBackground;
58 | border-color: @infoBorder;
59 | color: @infoText;
60 | }
61 | .alert-info h4 {
62 | color: @infoText;
63 | }
64 |
65 |
66 | // Block alerts
67 | // -------------------------
68 |
69 | .alert-block {
70 | padding-top: 14px;
71 | padding-bottom: 14px;
72 | }
73 | .alert-block > p,
74 | .alert-block > ul {
75 | margin-bottom: 0;
76 | }
77 | .alert-block p + p {
78 | margin-top: 5px;
79 | }
80 |
--------------------------------------------------------------------------------
/book/bootstrap/less/bootstrap.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v2.3.2
3 | *
4 | * Copyright 2013 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world by @mdo and @fat.
9 | */
10 |
11 | // Core variables and mixins
12 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc
13 | @import "mixins.less";
14 |
15 | // CSS Reset
16 | @import "reset.less";
17 |
18 | // Grid system and page structure
19 | @import "scaffolding.less";
20 | @import "grid.less";
21 | @import "layouts.less";
22 |
23 | // Base CSS
24 | @import "type.less";
25 | @import "code.less";
26 | // @import "forms.less";
27 | @import "tables.less";
28 |
29 | // Components: common
30 | // @import "sprites.less";
31 | // @import "dropdowns.less";
32 | @import "wells.less";
33 | @import "component-animations.less";
34 | @import "close.less";
35 |
36 | // Components: Buttons & Alerts
37 | @import "buttons.less";
38 | // @import "button-groups.less";
39 | @import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
40 |
41 | // Components: Nav
42 | @import "navs.less";
43 | @import "navbar.less";
44 | @import "breadcrumbs.less";
45 | // @import "pagination.less";
46 | // @import "pager.less";
47 |
48 | // Components: Popovers
49 | @import "modals.less";
50 | @import "tooltip.less";
51 | @import "popovers.less";
52 |
53 | // Components: Misc
54 | @import "thumbnails.less";
55 | @import "media.less";
56 | @import "labels-badges.less";
57 | // @import "progress-bars.less";
58 | // @import "accordion.less";
59 | // @import "carousel.less";
60 | // @import "hero-unit.less";
61 |
62 | // Utility classes
63 | @import "utilities.less"; // Has to be last to override when necessary
64 |
--------------------------------------------------------------------------------
/book/bootstrap/less/breadcrumbs.less:
--------------------------------------------------------------------------------
1 | //
2 | // Breadcrumbs
3 | // --------------------------------------------------
4 |
5 |
6 | .breadcrumb {
7 | padding: 8px 15px;
8 | margin: 0 0 @baseLineHeight;
9 | list-style: none;
10 | background-color: #f5f5f5;
11 | .border-radius(@baseBorderRadius);
12 | > li {
13 | display: inline-block;
14 | .ie7-inline-block();
15 | text-shadow: 0 1px 0 @white;
16 | > .divider {
17 | padding: 0 5px;
18 | color: #ccc;
19 | }
20 | }
21 | > .active {
22 | color: @grayLight;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/book/bootstrap/less/carousel.less:
--------------------------------------------------------------------------------
1 | //
2 | // Carousel
3 | // --------------------------------------------------
4 |
5 |
6 | .carousel {
7 | position: relative;
8 | margin-bottom: @baseLineHeight;
9 | line-height: 1;
10 | }
11 |
12 | .carousel-inner {
13 | overflow: hidden;
14 | width: 100%;
15 | position: relative;
16 | }
17 |
18 | .carousel-inner {
19 |
20 | > .item {
21 | display: none;
22 | position: relative;
23 | .transition(.6s ease-in-out left);
24 |
25 | // Account for jankitude on images
26 | > img,
27 | > a > img {
28 | display: block;
29 | line-height: 1;
30 | }
31 | }
32 |
33 | > .active,
34 | > .next,
35 | > .prev { display: block; }
36 |
37 | > .active {
38 | left: 0;
39 | }
40 |
41 | > .next,
42 | > .prev {
43 | position: absolute;
44 | top: 0;
45 | width: 100%;
46 | }
47 |
48 | > .next {
49 | left: 100%;
50 | }
51 | > .prev {
52 | left: -100%;
53 | }
54 | > .next.left,
55 | > .prev.right {
56 | left: 0;
57 | }
58 |
59 | > .active.left {
60 | left: -100%;
61 | }
62 | > .active.right {
63 | left: 100%;
64 | }
65 |
66 | }
67 |
68 | // Left/right controls for nav
69 | // ---------------------------
70 |
71 | .carousel-control {
72 | position: absolute;
73 | top: 40%;
74 | left: 15px;
75 | width: 40px;
76 | height: 40px;
77 | margin-top: -20px;
78 | font-size: 60px;
79 | font-weight: 100;
80 | line-height: 30px;
81 | color: @white;
82 | text-align: center;
83 | background: @grayDarker;
84 | border: 3px solid @white;
85 | .border-radius(23px);
86 | .opacity(50);
87 |
88 | // we can't have this transition here
89 | // because webkit cancels the carousel
90 | // animation if you trip this while
91 | // in the middle of another animation
92 | // ;_;
93 | // .transition(opacity .2s linear);
94 |
95 | // Reposition the right one
96 | &.right {
97 | left: auto;
98 | right: 15px;
99 | }
100 |
101 | // Hover/focus state
102 | &:hover,
103 | &:focus {
104 | color: @white;
105 | text-decoration: none;
106 | .opacity(90);
107 | }
108 | }
109 |
110 | // Carousel indicator pips
111 | // -----------------------------
112 | .carousel-indicators {
113 | position: absolute;
114 | top: 15px;
115 | right: 15px;
116 | z-index: 5;
117 | margin: 0;
118 | list-style: none;
119 |
120 | li {
121 | display: block;
122 | float: left;
123 | width: 10px;
124 | height: 10px;
125 | margin-left: 5px;
126 | text-indent: -999px;
127 | background-color: #ccc;
128 | background-color: rgba(255,255,255,.25);
129 | border-radius: 5px;
130 | }
131 | .active {
132 | background-color: #fff;
133 | }
134 | }
135 |
136 | // Caption for text below images
137 | // -----------------------------
138 |
139 | .carousel-caption {
140 | position: absolute;
141 | left: 0;
142 | right: 0;
143 | bottom: 0;
144 | padding: 15px;
145 | background: @grayDark;
146 | background: rgba(0,0,0,.75);
147 | }
148 | .carousel-caption h4,
149 | .carousel-caption p {
150 | color: @white;
151 | line-height: @baseLineHeight;
152 | }
153 | .carousel-caption h4 {
154 | margin: 0 0 5px;
155 | }
156 | .carousel-caption p {
157 | margin-bottom: 0;
158 | }
159 |
--------------------------------------------------------------------------------
/book/bootstrap/less/close.less:
--------------------------------------------------------------------------------
1 | //
2 | // Close icons
3 | // --------------------------------------------------
4 |
5 |
6 | .close {
7 | float: right;
8 | font-size: 20px;
9 | font-weight: bold;
10 | line-height: @baseLineHeight;
11 | color: @black;
12 | text-shadow: 0 1px 0 rgba(255,255,255,1);
13 | .opacity(20);
14 | &:hover,
15 | &:focus {
16 | color: @black;
17 | text-decoration: none;
18 | cursor: pointer;
19 | .opacity(40);
20 | }
21 | }
22 |
23 | // Additional properties for button version
24 | // iOS requires the button element instead of an anchor tag.
25 | // If you want the anchor version, it requires `href="#"`.
26 | button.close {
27 | padding: 0;
28 | cursor: pointer;
29 | background: transparent;
30 | border: 0;
31 | -webkit-appearance: none;
32 | }
--------------------------------------------------------------------------------
/book/bootstrap/less/code.less:
--------------------------------------------------------------------------------
1 | //
2 | // Code (inline and blocK)
3 | // --------------------------------------------------
4 |
5 |
6 | // Inline and block code styles
7 | code,
8 | pre {
9 | padding: 0 3px 2px;
10 | #font > #family > .monospace;
11 | font-size: @baseFontSize - 2;
12 | color: @grayDark;
13 | // .border-radius(3px);
14 | }
15 |
16 | // Inline code
17 | code {
18 | padding: 2px 4px;
19 | color: #0B0B61;
20 | background-color: #EFEFFB;
21 | white-space: nowrap;
22 | }
23 |
24 | // Small code
25 | small code {
26 | font-size: @baseFontSize - 4;
27 | }
28 |
29 | // Blocks of code
30 | pre {
31 | display: block;
32 | padding: (@baseLineHeight - 1) / 2;
33 | margin: 0 0 @baseLineHeight / 2;
34 | font-size: @baseFontSize - 1; // 14px to 13px
35 | line-height: @baseLineHeight;
36 | // word-break: break-all;
37 | // word-wrap: break-word;
38 | // white-space: pre;
39 | // white-space: pre-wrap;
40 | background-color: #EFFBFB;
41 | border: 1px solid #ccc; // fallback for IE7-8
42 | border: 1px solid rgba(0,0,0,.15);
43 | border-right: 3px solid #8181F7;
44 | border-bottom: 3px solid #8181F7;
45 |
46 | // Make prettyprint styles more spaced out for readability
47 | &.prettyprint {
48 | margin-bottom: @baseLineHeight;
49 | }
50 |
51 | // Account for some code outputs that place code tags in pre tags
52 | code {
53 | padding: 0;
54 | color: inherit;
55 | white-space: pre;
56 | white-space: pre-wrap;
57 | background-color: transparent;
58 | border: 0;
59 | }
60 | }
61 |
62 | // Enable scrollable blocks of code
63 | .pre-scrollable {
64 | max-height: 340px;
65 | overflow-y: scroll;
66 | }
67 |
68 | // Make base font size lesser in scripts
69 | div.well pre {
70 | font-size: @baseFontSize - 4;
71 | }
--------------------------------------------------------------------------------
/book/bootstrap/less/component-animations.less:
--------------------------------------------------------------------------------
1 | //
2 | // Component animations
3 | // --------------------------------------------------
4 |
5 |
6 | .fade {
7 | opacity: 0;
8 | .transition(opacity .15s linear);
9 | &.in {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | .collapse {
15 | position: relative;
16 | height: 0;
17 | overflow: hidden;
18 | .transition(height .35s ease);
19 | &.in {
20 | height: auto;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/book/bootstrap/less/grid.less:
--------------------------------------------------------------------------------
1 | //
2 | // Grid system
3 | // --------------------------------------------------
4 |
5 |
6 | // Fixed (940px)
7 | #grid > .core(@gridColumnWidth, @gridGutterWidth);
8 |
9 | // Fluid (940px)
10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
11 |
12 | // Reset utility classes due to specificity
13 | [class*="span"].hide,
14 | .row-fluid [class*="span"].hide {
15 | display: none;
16 | }
17 |
18 | [class*="span"].pull-right,
19 | .row-fluid [class*="span"].pull-right {
20 | float: right;
21 | }
22 |
--------------------------------------------------------------------------------
/book/bootstrap/less/hero-unit.less:
--------------------------------------------------------------------------------
1 | //
2 | // Hero unit
3 | // --------------------------------------------------
4 |
5 |
6 | .hero-unit {
7 | padding: 60px;
8 | margin-bottom: 30px;
9 | font-size: 18px;
10 | font-weight: 200;
11 | line-height: @baseLineHeight * 1.5;
12 | color: @heroUnitLeadColor;
13 | background-color: @heroUnitBackground;
14 | .border-radius(6px);
15 | h1 {
16 | margin-bottom: 0;
17 | font-size: 60px;
18 | line-height: 1;
19 | color: @heroUnitHeadingColor;
20 | letter-spacing: -1px;
21 | }
22 | li {
23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/book/bootstrap/less/labels-badges.less:
--------------------------------------------------------------------------------
1 | //
2 | // Labels and badges
3 | // --------------------------------------------------
4 |
5 |
6 | // Base classes
7 | .label,
8 | .badge {
9 | display: inline-block;
10 | padding: 2px 4px;
11 | font-size: @baseFontSize * .846;
12 | font-weight: bold;
13 | line-height: 14px; // ensure proper line-height if floated
14 | color: @white;
15 | vertical-align: baseline;
16 | white-space: nowrap;
17 | text-shadow: 0 -1px 0 rgba(0,0,0,.25);
18 | background-color: @grayLight;
19 | }
20 | // Set unique padding and border-radii
21 | .label {
22 | .border-radius(3px);
23 | }
24 | .badge {
25 | padding-left: 9px;
26 | padding-right: 9px;
27 | .border-radius(9px);
28 | }
29 |
30 | // Empty labels/badges collapse
31 | .label,
32 | .badge {
33 | &:empty {
34 | display: none;
35 | }
36 | }
37 |
38 | // Hover/focus state, but only for links
39 | a {
40 | &.label:hover,
41 | &.label:focus,
42 | &.badge:hover,
43 | &.badge:focus {
44 | color: @white;
45 | text-decoration: none;
46 | cursor: pointer;
47 | }
48 | }
49 |
50 | // Colors
51 | // Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute)
52 | .label,
53 | .badge {
54 | // Important (red)
55 | &-important { background-color: @errorText; }
56 | &-important[href] { background-color: darken(@errorText, 10%); }
57 | // Warnings (orange)
58 | &-warning { background-color: @orange; }
59 | &-warning[href] { background-color: darken(@orange, 10%); }
60 | // Success (green)
61 | &-success { background-color: @successText; }
62 | &-success[href] { background-color: darken(@successText, 10%); }
63 | // Info (turquoise)
64 | &-info { background-color: @infoText; }
65 | &-info[href] { background-color: darken(@infoText, 10%); }
66 | // Inverse (black)
67 | &-inverse { background-color: @grayDark; }
68 | &-inverse[href] { background-color: darken(@grayDark, 10%); }
69 | }
70 |
71 | // Quick fix for labels/badges in buttons
72 | .btn {
73 | .label,
74 | .badge {
75 | position: relative;
76 | top: -1px;
77 | }
78 | }
79 | .btn-mini {
80 | .label,
81 | .badge {
82 | top: 0;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/book/bootstrap/less/layouts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Layouts
3 | // --------------------------------------------------
4 |
5 |
6 | // Container (centered, fixed-width layouts)
7 | .container {
8 | .container-fixed();
9 | }
10 |
11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content)
12 | .container-fluid {
13 | padding-right: @gridGutterWidth;
14 | padding-left: @gridGutterWidth;
15 | .clearfix();
16 | }
--------------------------------------------------------------------------------
/book/bootstrap/less/media.less:
--------------------------------------------------------------------------------
1 | // Media objects
2 | // Source: http://stubbornella.org/content/?p=497
3 | // --------------------------------------------------
4 |
5 |
6 | // Common styles
7 | // -------------------------
8 |
9 | // Clear the floats
10 | .media,
11 | .media-body {
12 | overflow: hidden;
13 | *overflow: visible;
14 | zoom: 1;
15 | }
16 |
17 | // Proper spacing between instances of .media
18 | .media,
19 | .media .media {
20 | margin-top: 15px;
21 | }
22 | .media:first-child {
23 | margin-top: 0;
24 | }
25 |
26 | // For images and videos, set to block
27 | .media-object {
28 | display: block;
29 | }
30 |
31 | // Reset margins on headings for tighter default spacing
32 | .media-heading {
33 | margin: 0 0 5px;
34 | }
35 |
36 |
37 | // Media image alignment
38 | // -------------------------
39 |
40 | .media > .pull-left {
41 | margin-right: 10px;
42 | }
43 | .media > .pull-right {
44 | margin-left: 10px;
45 | }
46 |
47 |
48 | // Media list variation
49 | // -------------------------
50 |
51 | // Undo default ul/ol styles
52 | .media-list {
53 | margin-left: 0;
54 | list-style: none;
55 | }
56 |
--------------------------------------------------------------------------------
/book/bootstrap/less/modals.less:
--------------------------------------------------------------------------------
1 | //
2 | // Modals
3 | // --------------------------------------------------
4 |
5 | // Background
6 | .modal-backdrop {
7 | position: fixed;
8 | top: 0;
9 | right: 0;
10 | bottom: 0;
11 | left: 0;
12 | z-index: @zindexModalBackdrop;
13 | background-color: @black;
14 | // Fade for backdrop
15 | &.fade { opacity: 0; }
16 | }
17 |
18 | .modal-backdrop,
19 | .modal-backdrop.fade.in {
20 | .opacity(80);
21 | }
22 |
23 | // Base modal
24 | .modal {
25 | position: fixed;
26 | top: 10%;
27 | left: 50%;
28 | z-index: @zindexModal;
29 | width: 560px;
30 | margin-left: -280px;
31 | background-color: @white;
32 | border: 1px solid #999;
33 | border: 1px solid rgba(0,0,0,.3);
34 | *border: 1px solid #999; /* IE6-7 */
35 | .border-radius(6px);
36 | .box-shadow(0 3px 7px rgba(0,0,0,0.3));
37 | .background-clip(padding-box);
38 | // Remove focus outline from opened modal
39 | outline: none;
40 |
41 | &.fade {
42 | .transition(e('opacity .3s linear, top .3s ease-out'));
43 | top: -25%;
44 | }
45 | &.fade.in { top: 10%; }
46 | }
47 | .modal-header {
48 | padding: 9px 15px;
49 | border-bottom: 1px solid #eee;
50 | // Close icon
51 | .close { margin-top: 2px; }
52 | // Heading
53 | h3 {
54 | margin: 0;
55 | line-height: 30px;
56 | }
57 | }
58 |
59 | // Body (where all modal content resides)
60 | .modal-body {
61 | position: relative;
62 | overflow-y: auto;
63 | max-height: 400px;
64 | padding: 15px;
65 | }
66 | // Remove bottom margin if need be
67 | .modal-form {
68 | margin-bottom: 0;
69 | }
70 |
71 | // Footer (for actions)
72 | .modal-footer {
73 | padding: 14px 15px 15px;
74 | margin-bottom: 0;
75 | text-align: right; // right align buttons
76 | background-color: #f5f5f5;
77 | border-top: 1px solid #ddd;
78 | .border-radius(0 0 6px 6px);
79 | .box-shadow(inset 0 1px 0 @white);
80 | .clearfix(); // clear it in case folks use .pull-* classes on buttons
81 |
82 | // Properly space out buttons
83 | .btn + .btn {
84 | margin-left: 5px;
85 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
86 | }
87 | // but override that for button groups
88 | .btn-group .btn + .btn {
89 | margin-left: -1px;
90 | }
91 | // and override it for block buttons as well
92 | .btn-block + .btn-block {
93 | margin-left: 0;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/book/bootstrap/less/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | margin: @baseLineHeight 0;
8 | list-style: none;
9 | text-align: center;
10 | .clearfix();
11 | }
12 | .pager li {
13 | display: inline;
14 | }
15 | .pager li > a,
16 | .pager li > span {
17 | display: inline-block;
18 | padding: 5px 14px;
19 | background-color: #fff;
20 | border: 1px solid #ddd;
21 | .border-radius(15px);
22 | }
23 | .pager li > a:hover,
24 | .pager li > a:focus {
25 | text-decoration: none;
26 | background-color: #f5f5f5;
27 | }
28 | .pager .next > a,
29 | .pager .next > span {
30 | float: right;
31 | }
32 | .pager .previous > a,
33 | .pager .previous > span {
34 | float: left;
35 | }
36 | .pager .disabled > a,
37 | .pager .disabled > a:hover,
38 | .pager .disabled > a:focus,
39 | .pager .disabled > span {
40 | color: @grayLight;
41 | background-color: #fff;
42 | cursor: default;
43 | }
--------------------------------------------------------------------------------
/book/bootstrap/less/pagination.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination (multiple pages)
3 | // --------------------------------------------------
4 |
5 | // Space out pagination from surrounding content
6 | .pagination {
7 | margin: @baseLineHeight 0;
8 | }
9 |
10 | .pagination ul {
11 | // Allow for text-based alignment
12 | display: inline-block;
13 | .ie7-inline-block();
14 | // Reset default ul styles
15 | margin-left: 0;
16 | margin-bottom: 0;
17 | // Visuals
18 | .border-radius(@baseBorderRadius);
19 | .box-shadow(0 1px 2px rgba(0,0,0,.05));
20 | }
21 | .pagination ul > li {
22 | display: inline; // Remove list-style and block-level defaults
23 | }
24 | .pagination ul > li > a,
25 | .pagination ul > li > span {
26 | float: left; // Collapse white-space
27 | padding: 4px 12px;
28 | line-height: @baseLineHeight;
29 | text-decoration: none;
30 | background-color: @paginationBackground;
31 | border: 1px solid @paginationBorder;
32 | border-left-width: 0;
33 | }
34 | .pagination ul > li > a:hover,
35 | .pagination ul > li > a:focus,
36 | .pagination ul > .active > a,
37 | .pagination ul > .active > span {
38 | background-color: @paginationActiveBackground;
39 | }
40 | .pagination ul > .active > a,
41 | .pagination ul > .active > span {
42 | color: @grayLight;
43 | cursor: default;
44 | }
45 | .pagination ul > .disabled > span,
46 | .pagination ul > .disabled > a,
47 | .pagination ul > .disabled > a:hover,
48 | .pagination ul > .disabled > a:focus {
49 | color: @grayLight;
50 | background-color: transparent;
51 | cursor: default;
52 | }
53 | .pagination ul > li:first-child > a,
54 | .pagination ul > li:first-child > span {
55 | border-left-width: 1px;
56 | .border-left-radius(@baseBorderRadius);
57 | }
58 | .pagination ul > li:last-child > a,
59 | .pagination ul > li:last-child > span {
60 | .border-right-radius(@baseBorderRadius);
61 | }
62 |
63 |
64 | // Alignment
65 | // --------------------------------------------------
66 |
67 | .pagination-centered {
68 | text-align: center;
69 | }
70 | .pagination-right {
71 | text-align: right;
72 | }
73 |
74 |
75 | // Sizing
76 | // --------------------------------------------------
77 |
78 | // Large
79 | .pagination-large {
80 | ul > li > a,
81 | ul > li > span {
82 | padding: @paddingLarge;
83 | font-size: @fontSizeLarge;
84 | }
85 | ul > li:first-child > a,
86 | ul > li:first-child > span {
87 | .border-left-radius(@borderRadiusLarge);
88 | }
89 | ul > li:last-child > a,
90 | ul > li:last-child > span {
91 | .border-right-radius(@borderRadiusLarge);
92 | }
93 | }
94 |
95 | // Small and mini
96 | .pagination-mini,
97 | .pagination-small {
98 | ul > li:first-child > a,
99 | ul > li:first-child > span {
100 | .border-left-radius(@borderRadiusSmall);
101 | }
102 | ul > li:last-child > a,
103 | ul > li:last-child > span {
104 | .border-right-radius(@borderRadiusSmall);
105 | }
106 | }
107 |
108 | // Small
109 | .pagination-small {
110 | ul > li > a,
111 | ul > li > span {
112 | padding: @paddingSmall;
113 | font-size: @fontSizeSmall;
114 | }
115 | }
116 | // Mini
117 | .pagination-mini {
118 | ul > li > a,
119 | ul > li > span {
120 | padding: @paddingMini;
121 | font-size: @fontSizeMini;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/book/bootstrap/less/progress-bars.less:
--------------------------------------------------------------------------------
1 | //
2 | // Progress bars
3 | // --------------------------------------------------
4 |
5 |
6 | // ANIMATIONS
7 | // ----------
8 |
9 | // Webkit
10 | @-webkit-keyframes progress-bar-stripes {
11 | from { background-position: 40px 0; }
12 | to { background-position: 0 0; }
13 | }
14 |
15 | // Firefox
16 | @-moz-keyframes progress-bar-stripes {
17 | from { background-position: 40px 0; }
18 | to { background-position: 0 0; }
19 | }
20 |
21 | // IE9
22 | @-ms-keyframes progress-bar-stripes {
23 | from { background-position: 40px 0; }
24 | to { background-position: 0 0; }
25 | }
26 |
27 | // Opera
28 | @-o-keyframes progress-bar-stripes {
29 | from { background-position: 0 0; }
30 | to { background-position: 40px 0; }
31 | }
32 |
33 | // Spec
34 | @keyframes progress-bar-stripes {
35 | from { background-position: 40px 0; }
36 | to { background-position: 0 0; }
37 | }
38 |
39 |
40 |
41 | // THE BARS
42 | // --------
43 |
44 | // Outer container
45 | .progress {
46 | overflow: hidden;
47 | height: @baseLineHeight;
48 | margin-bottom: @baseLineHeight;
49 | #gradient > .vertical(#f5f5f5, #f9f9f9);
50 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
51 | .border-radius(@baseBorderRadius);
52 | }
53 |
54 | // Bar of progress
55 | .progress .bar {
56 | width: 0%;
57 | height: 100%;
58 | color: @white;
59 | float: left;
60 | font-size: 12px;
61 | text-align: center;
62 | text-shadow: 0 -1px 0 rgba(0,0,0,.25);
63 | #gradient > .vertical(#149bdf, #0480be);
64 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
65 | .box-sizing(border-box);
66 | .transition(width .6s ease);
67 | }
68 | .progress .bar + .bar {
69 | .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)");
70 | }
71 |
72 | // Striped bars
73 | .progress-striped .bar {
74 | #gradient > .striped(#149bdf);
75 | .background-size(40px 40px);
76 | }
77 |
78 | // Call animation for the active one
79 | .progress.active .bar {
80 | -webkit-animation: progress-bar-stripes 2s linear infinite;
81 | -moz-animation: progress-bar-stripes 2s linear infinite;
82 | -ms-animation: progress-bar-stripes 2s linear infinite;
83 | -o-animation: progress-bar-stripes 2s linear infinite;
84 | animation: progress-bar-stripes 2s linear infinite;
85 | }
86 |
87 |
88 |
89 | // COLORS
90 | // ------
91 |
92 | // Danger (red)
93 | .progress-danger .bar, .progress .bar-danger {
94 | #gradient > .vertical(#ee5f5b, #c43c35);
95 | }
96 | .progress-danger.progress-striped .bar, .progress-striped .bar-danger {
97 | #gradient > .striped(#ee5f5b);
98 | }
99 |
100 | // Success (green)
101 | .progress-success .bar, .progress .bar-success {
102 | #gradient > .vertical(#62c462, #57a957);
103 | }
104 | .progress-success.progress-striped .bar, .progress-striped .bar-success {
105 | #gradient > .striped(#62c462);
106 | }
107 |
108 | // Info (teal)
109 | .progress-info .bar, .progress .bar-info {
110 | #gradient > .vertical(#5bc0de, #339bb9);
111 | }
112 | .progress-info.progress-striped .bar, .progress-striped .bar-info {
113 | #gradient > .striped(#5bc0de);
114 | }
115 |
116 | // Warning (orange)
117 | .progress-warning .bar, .progress .bar-warning {
118 | #gradient > .vertical(lighten(@orange, 15%), @orange);
119 | }
120 | .progress-warning.progress-striped .bar, .progress-striped .bar-warning {
121 | #gradient > .striped(lighten(@orange, 15%));
122 | }
123 |
--------------------------------------------------------------------------------
/book/bootstrap/less/responsive-1200px-min.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Large desktop and up
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 1200px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);
16 |
17 | // Thumbnails
18 | .thumbnails {
19 | margin-left: -@gridGutterWidth1200;
20 | }
21 | .thumbnails > li {
22 | margin-left: @gridGutterWidth1200;
23 | }
24 | .row-fluid .thumbnails {
25 | margin-left: 0;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/book/bootstrap/less/responsive-768px-979px.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Tablet to desktop
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 768px) and (max-width: 979px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768);
16 |
17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/book/bootstrap/less/responsive-utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // IE10 Metro responsive
7 | // Required for Windows 8 Metro split-screen snapping with IE10
8 | // Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/
9 | @-ms-viewport{
10 | width: device-width;
11 | }
12 |
13 | // Hide from screenreaders and browsers
14 | // Credit: HTML5 Boilerplate
15 | .hidden {
16 | display: none;
17 | visibility: hidden;
18 | }
19 |
20 | // Visibility utilities
21 |
22 | // For desktops
23 | .visible-phone { display: none !important; }
24 | .visible-tablet { display: none !important; }
25 | .hidden-phone { }
26 | .hidden-tablet { }
27 | .hidden-desktop { display: none !important; }
28 | .visible-desktop { display: inherit !important; }
29 |
30 | // Tablets & small desktops only
31 | @media (min-width: 768px) and (max-width: 979px) {
32 | // Hide everything else
33 | .hidden-desktop { display: inherit !important; }
34 | .visible-desktop { display: none !important ; }
35 | // Show
36 | .visible-tablet { display: inherit !important; }
37 | // Hide
38 | .hidden-tablet { display: none !important; }
39 | }
40 |
41 | // Phones only
42 | @media (max-width: 767px) {
43 | // Hide everything else
44 | .hidden-desktop { display: inherit !important; }
45 | .visible-desktop { display: none !important; }
46 | // Show
47 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior
48 | // Hide
49 | .hidden-phone { display: none !important; }
50 | }
51 |
52 | // Print utilities
53 | .visible-print { display: none !important; }
54 | .hidden-print { }
55 |
56 | @media print {
57 | .visible-print { display: inherit !important; }
58 | .hidden-print { display: none !important; }
59 | }
60 |
--------------------------------------------------------------------------------
/book/bootstrap/less/responsive.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.3.2
3 | *
4 | * Copyright 2013 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world by @mdo and @fat.
9 | */
10 |
11 |
12 | // Responsive.less
13 | // For phone and tablet devices
14 | // -------------------------------------------------------------
15 |
16 |
17 | // REPEAT VARIABLES & MIXINS
18 | // -------------------------
19 | // Required since we compile the responsive stuff separately
20 |
21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc
22 | @import "mixins.less";
23 |
24 |
25 | // RESPONSIVE CLASSES
26 | // ------------------
27 |
28 | @import "responsive-utilities.less";
29 |
30 |
31 | // MEDIA QUERIES
32 | // ------------------
33 |
34 | // Large desktops
35 | @import "responsive-1200px-min.less";
36 |
37 | // Tablets to regular desktops
38 | @import "responsive-768px-979px.less";
39 |
40 | // Phones to portrait tablets and narrow desktops
41 | @import "responsive-767px-max.less";
42 |
43 |
44 | // RESPONSIVE NAVBAR
45 | // ------------------
46 |
47 | // From 979px and below, show a button to toggle navbar contents
48 | @import "responsive-navbar.less";
49 |
--------------------------------------------------------------------------------
/book/bootstrap/less/scaffolding.less:
--------------------------------------------------------------------------------
1 | //
2 | // Scaffolding
3 | // --------------------------------------------------
4 |
5 |
6 | // Body reset
7 | // -------------------------
8 |
9 | body {
10 | margin: 0;
11 | font-family: @baseFontFamily;
12 | font-size: @baseFontSize;
13 | line-height: @baseLineHeight;
14 | color: @textColor;
15 | background-color: @bodyBackground;
16 | }
17 |
18 |
19 | // Links
20 | // -------------------------
21 |
22 | a {
23 | color: @linkColor;
24 | text-decoration: none;
25 | }
26 | a:hover,
27 | a:focus {
28 | color: @linkColorHover;
29 | text-decoration: underline;
30 | }
31 |
32 |
33 | // Images
34 | // -------------------------
35 |
36 | // Rounded corners
37 | .img-rounded {
38 | .border-radius(6px);
39 | }
40 |
41 | // Add polaroid-esque trim
42 | .img-polaroid {
43 | padding: 4px;
44 | background-color: #fff;
45 | border: 1px solid #ccc;
46 | border: 1px solid rgba(0,0,0,.2);
47 | .box-shadow(0 1px 3px rgba(0,0,0,.1));
48 | }
49 |
50 | // Perfect circle
51 | .img-circle {
52 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images
53 | }
54 |
--------------------------------------------------------------------------------
/book/bootstrap/less/thumbnails.less:
--------------------------------------------------------------------------------
1 | //
2 | // Thumbnails
3 | // --------------------------------------------------
4 |
5 |
6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files
7 |
8 | // Make wrapper ul behave like the grid
9 | .thumbnails {
10 | margin-left: -@gridGutterWidth;
11 | list-style: none;
12 | .clearfix();
13 | }
14 | // Fluid rows have no left margin
15 | .row-fluid .thumbnails {
16 | margin-left: 0;
17 | }
18 |
19 | // Float li to make thumbnails appear in a row
20 | .thumbnails > li {
21 | float: left; // Explicity set the float since we don't require .span* classes
22 | margin-bottom: @baseLineHeight;
23 | margin-left: @gridGutterWidth;
24 | }
25 |
26 | // The actual thumbnail (can be `a` or `div`)
27 | .thumbnail {
28 | display: block;
29 | padding: 4px;
30 | line-height: @baseLineHeight;
31 | border: 1px solid #ddd;
32 | .border-radius(@baseBorderRadius);
33 | .box-shadow(0 1px 3px rgba(0,0,0,.055));
34 | .transition(all .2s ease-in-out);
35 | }
36 | // Add a hover/focus state for linked versions only
37 | a.thumbnail:hover,
38 | a.thumbnail:focus {
39 | border-color: @linkColor;
40 | .box-shadow(0 1px 4px rgba(0,105,214,.25));
41 | }
42 |
43 | // Images and captions
44 | .thumbnail > img {
45 | display: block;
46 | max-width: 100%;
47 | margin-left: auto;
48 | margin-right: auto;
49 | }
50 | .thumbnail .caption {
51 | padding: 9px;
52 | color: @gray;
53 | }
54 |
--------------------------------------------------------------------------------
/book/bootstrap/less/tooltip.less:
--------------------------------------------------------------------------------
1 | //
2 | // Tooltips
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .tooltip {
8 | position: absolute;
9 | z-index: @zindexTooltip;
10 | display: block;
11 | visibility: visible;
12 | font-size: 11px;
13 | line-height: 1.4;
14 | .opacity(0);
15 | &.in { .opacity(80); }
16 | &.top { margin-top: -3px; padding: 5px 0; }
17 | &.right { margin-left: 3px; padding: 0 5px; }
18 | &.bottom { margin-top: 3px; padding: 5px 0; }
19 | &.left { margin-left: -3px; padding: 0 5px; }
20 | }
21 |
22 | // Wrapper for the tooltip content
23 | .tooltip-inner {
24 | max-width: 200px;
25 | padding: 8px;
26 | color: @tooltipColor;
27 | text-align: center;
28 | text-decoration: none;
29 | background-color: @tooltipBackground;
30 | .border-radius(@baseBorderRadius);
31 | }
32 |
33 | // Arrows
34 | .tooltip-arrow {
35 | position: absolute;
36 | width: 0;
37 | height: 0;
38 | border-color: transparent;
39 | border-style: solid;
40 | }
41 | .tooltip {
42 | &.top .tooltip-arrow {
43 | bottom: 0;
44 | left: 50%;
45 | margin-left: -@tooltipArrowWidth;
46 | border-width: @tooltipArrowWidth @tooltipArrowWidth 0;
47 | border-top-color: @tooltipArrowColor;
48 | }
49 | &.right .tooltip-arrow {
50 | top: 50%;
51 | left: 0;
52 | margin-top: -@tooltipArrowWidth;
53 | border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0;
54 | border-right-color: @tooltipArrowColor;
55 | }
56 | &.left .tooltip-arrow {
57 | top: 50%;
58 | right: 0;
59 | margin-top: -@tooltipArrowWidth;
60 | border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth;
61 | border-left-color: @tooltipArrowColor;
62 | }
63 | &.bottom .tooltip-arrow {
64 | top: 0;
65 | left: 50%;
66 | margin-left: -@tooltipArrowWidth;
67 | border-width: 0 @tooltipArrowWidth @tooltipArrowWidth;
68 | border-bottom-color: @tooltipArrowColor;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/book/bootstrap/less/utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // Quick floats
7 | .pull-right {
8 | float: right;
9 | }
10 | .pull-left {
11 | float: left;
12 | }
13 |
14 | // Toggling content
15 | .hide {
16 | display: none;
17 | }
18 | .show {
19 | display: block;
20 | }
21 |
22 | // Visibility
23 | .invisible {
24 | visibility: hidden;
25 | }
26 |
27 | // For Affix plugin
28 | .affix {
29 | position: fixed;
30 | }
31 |
--------------------------------------------------------------------------------
/book/bootstrap/less/wells.less:
--------------------------------------------------------------------------------
1 | //
2 | // Wells
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .well {
8 | min-height: 20px;
9 | padding: 19px;
10 | margin-bottom: 20px;
11 | background-color: @wellBackground;
12 | border: 1px solid darken(@wellBackground, 7%);
13 | .border-radius(@baseBorderRadius);
14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15 | blockquote {
16 | border-color: #ddd;
17 | border-color: rgba(0,0,0,.15);
18 | }
19 | }
20 |
21 | // Sizes
22 | .well-large {
23 | padding: 24px;
24 | .border-radius(@borderRadiusLarge);
25 | }
26 | .well-small {
27 | padding: 9px;
28 | .border-radius(@borderRadiusSmall);
29 | }
30 |
--------------------------------------------------------------------------------
/book/epub.css:
--------------------------------------------------------------------------------
1 | /* incut styles */
2 |
3 | div.incut {
4 | margin-left: 1em;
5 | }
6 | .incut-DEF {
7 | background-color: #f2f2f2;
8 | }
9 | .incut-WARN {
10 | background-color: #ffccaa;
11 | }
12 | .incut-DANGER {
13 | background-color: #f4d7d7;
14 | }
15 | .incut-NOTE {
16 | background-color: #aaeeff;
17 | border-left: blue 3px solid;
18 | }
19 | .incut-INFO {
20 | background-color: #d5e5ff;
21 | }
22 |
23 |
24 | /* images */
25 | img {
26 | width: 100%;
27 | }
--------------------------------------------------------------------------------
/book/hints/ex1.md:
--------------------------------------------------------------------------------
1 | ### Exercise 1
2 |
3 | This exercise is intended to learn some features of dynamic tracing languages that was discussed in modules 1 and 2. First of all we need to pick probes that we will use in our tracing script. They would be parts of `syscall` provider/tapset. As you can remember from [stap command options][tools/systemtap#stap], probe parameters can be checked with `-L` option:
4 | ```
5 | # stap -L 'syscall.open'
6 | syscall.open name:string filename:string flags:long mode:long argstr:string $filename:long int $flags:long int $mode:long int
7 | # stap -L 'syscall.open.return'
8 | syscall.open.return name:string retstr:string $return:long int $filename:long int $flags:long int $mode:long int
9 | ```
10 | Same can be done for dtrace with `-l` option:
11 | ```
12 | # dtrace -l -f openat\* -v
13 | ID PROVIDER MODULE FUNCTION NAME
14 | 14167 syscall openat entry
15 | ...
16 | ```
17 |
18 | Return value (which would represent file descriptor number) will be saved into `$return` variable in SystemTap and `arg1` argument in DTrace. We will also need flags values: `arg2` in DTrace (because they are going third in `openat()` prototype). In SystemTap you can use either DWARF variable `$flags` or tapset variable `flags`. Latter is more stable.
19 |
20 | Similarly, path to opened file will be passed as second `openat()` argument and will be available in DTrace as `arg1` or `$filename`/`filename` in SystemTap. At the moment of system call, however, file path will be a string which is located in user address space, so to get it in tracing script, you will need to copy it by using `copyinstr()` in DTrace or one of `user_string*()` functions. Tapset variable already uses `user_string_quoted()` to access variable, so we will use it in our scripts.
21 |
22 | Note that data that we want gather is available in two different probes: flags and file path are provided by entry probe, while file descriptor number can only be collected in return probe (SystemTap can provide flags and file path in return probe, but as we mentioned, it depends on compiler optimizations). Since both probes will be executed in the same context, we can use [thread-local variables][lang/vars#thread-local-vars].
23 |
24 | Finally, stringifying flags will require usage of ternary operator `?:` in DTrace or `if/else` construct in SystemTap. To concatenate strings, use `strjoin` from DTrace or string concatenation operator `.` in SystemTap.
25 |
26 | Here are resulting DTrace script which implements required functionality:
27 |
28 | ````` scripts/dtrace/opentrace.d
29 |
30 | I have used `sprintf()` to concatenate strings in SystemTap version of a script:
31 |
32 | ````` scripts/stap/opentrace.stp
33 |
34 | Finally, you will need to add predicates to compare paths with `/etc` in DTrace by using `strstr()` subroutine and comparing it with `0` and SystemTap's `ininstr()` function.
35 |
--------------------------------------------------------------------------------
/book/hints/ex2.md:
--------------------------------------------------------------------------------
1 | ### Exercise 2
2 |
3 | We will have to use `count()` [aggregation][lang/assocarr#aggr] to count `open()` and `openat()` system calls. It can be cleaned up from outdated data with `trunc()` action in DTrace or `delete` operation in SystemTap. These scripts are roughly based on `wstat.d` and `wstat.stp` from [aggregations example][lang/assocarr#aggr-example].
4 |
5 | To print current timestamp we can use `%Y` formatting specifier and `walltimestamp` variable in DTrace. Same can be achieved with `ctime()` and `gettimeofday_s()` functions from SystemTap. To print data periodically, we can use [timer probes][lang/probes#timers]: `timer.s($1)` in SystemTap or `tick-$1s` from DTrace. `$1` here represents first command line argument.
6 |
7 | Finally, we need to determine if open operation requests creation of file or not. We should write predicate for that which tests flags passed to open for `O_CREAT` flag (we have learned how to access flags in previous exercise).
8 |
9 | Here are resulting scripts:
10 |
11 | ````` scripts/dtrace/openaggr.d
12 | ````` scripts/stap/openaggr.stp
13 |
14 |
--------------------------------------------------------------------------------
/book/hints/ex3.md:
--------------------------------------------------------------------------------
1 | ### Exercise 3
2 |
3 | #### Part 1
4 |
5 | In the first part of this exercise we will need to check which fields of `struct task_struct` in Linux or `proc_t` are responsible for which aspects of process functioning. You will need to apply following changes to dump task scripts: timer probe has to be replaced to a pair of probes: `proc:::exec-*` and `proc:::exit` in DTrace or `kprocess.exec_complete` and `kprocess.exit` in SystemTap. We have used exit probes for `execve()` system call to collect command line arguments: they are not filled in unless `execve()` call finishes.
6 |
7 | Here list of expected observations during this exercise:
8 |
9 | * When you run program with extra argument, it will be cleared in `main()` function, so you will see original argument in exec-probe, but only 'X' letters when program exits.
10 | * When you run program through symbolic link `lab3-1`, VFS node which refer to a binary file will point to a regular file `lab3`. That node is represented by `p_exec` field of `proc_t` in Solaris or `exe_file` of `task_struct` in Linux. `execname`, however, will behave differently in Solaris and Linux.
11 | * When you run program in chroot environment, root process directory will change from `/` to `/tmp/chroot`.
12 |
13 | Here are resulting scripts (they are not much different from original):
14 |
15 | ````` scripts/stap/dumptask-lab3.stp
16 | ````` scripts/dtrace/dumptask-lab3.d
17 |
18 | #### Part 2
19 |
20 | First of all we have to create several associative arrays which will use PID as a key (we can't use thread-local variables here because `exit()` can be called from any of process threads), and timestamp as a value. Final data will be kept in aggregations which we already learned in exercise 2.
21 |
22 | We will use probes from the section _Lifetime of a process_. They are shown in the following picture:
23 |
24 | 
25 |
26 | However, we do not know PID at the time `fork()` is called so we will use thread-local variable for that. We can check return value of `fork()` in return probe and re-use timestamp saved previously if everything went fine and `fork()` has returned value greater than 1 or throw it away.
27 |
28 | We wrote an ugly function `task_args()` to collect process arguments in `dumptask.stp` script. This data is available since SystemTap 2.5: `kprocess.exec` probe provides program's arguments in `argstr` argument. We will use `curpsinfo->pr_psargs` on Solaris as it keeps first 80 characters of command line to get rid of copying userspace arguments too. We will use `timestamp` variable in DTrace as a source of timestamps (again, a tautology). We will use `local_clock_us()` function as we do not care about CPU time skew.
29 |
30 | Finally, to reduce memory footprint in SystemTap, we will reduce associative arrays sizes. Here are resulting scripts:
31 |
32 | ````` scripts/stap/forktime.stp
33 | ````` scripts/dtrace/forktime.d
34 |
35 |
--------------------------------------------------------------------------------
/book/hints/ex5.md:
--------------------------------------------------------------------------------
1 | ### Exercise 5
2 |
3 | We will need to access pointer to `block_device` pointer in Linux to collect block device name and group data by it. As we know, main filesystem structure is called `super_block` which contains `s_bdev` pointer which has `struct block_device*`. SystemTap has two tapset functions, `MINOR()` and `MAJOR()` which allow to extract device number from `bd_dev` field of that structure. There is also an undocumented `bdevname()` function which is more convenient as it returns string, so we will use it.
4 |
5 | We will attach probes to `vfs_write()` and `vfs_read()` functions to trace filesystem operations. First argument of that functions is pointer to file of type `struct file*`. Amount of data being written or read is passed through argument `$count`.
6 |
7 | BIO level can be traced with `ioblock` tapset. We will do so by using its `ioblock.request` probe. It has following arguments: `bdev` -- `block_device` pointer, `size` -- amount of data in request, `rw` -- read or write flag which can be tested for equality with `BIO_READ` or `BIO_WRITE` constants.
8 |
9 | Here is resulting `deblock.stp` script:
10 |
11 | ````` scripts/stap/deblock.stp
12 |
13 | To trace readahead from part 2 we will need to replace `vfs_write` to `vfs_read`, `BIO_WRITE` to `BIO_READ` and get rid from amount of data in request saving into aggregation by replacing it with number of requests (which will be constant `1`).
14 |
15 | We can use `scsi.ioentry` probe to trace SCSI operations. We can actually detect which command was used by parsing CDB buffer, but we will omit that and will trace all SCSI operations. Getting device name, however is not that easy: `request` structure which is used in SCSI stack refers to `gendisk` and `hd_struct` structures, but they won't refer to `block_device` (on contrary, `block_device` itself refers them). So we will make a small trick: there is a linked list of structures `bio` ... `biotail` which refer block device structure the same way they do in BIO probes, so we will simply copy approach from `ioblock.request` probe.
16 |
17 | We will get `readahead.stp` script after applying all these modifications:
18 |
19 | ````` scripts/stap/readahead.stp
20 |
21 | One can get device name with `ddi_pathname()` action or `devinfo_t` translator (which uses it indirectly) which is applied to `buf` structure. Probes from `io` provider will do it automatically by passing resulting pseudo-structure as `args[1]` argument. Aside from name, it contains minor and major device names.
22 |
23 | Getting device name on VFS layer, however is harder: `vfs_t` structure which describes filesystem has only device number `vfs_dev`. ZFS makes things even harder: there is intermediate layer called pool which hides block devices from filesystem layer. So we will use mountpoints as an aggregation key. We will trace filesystem operations by attaching to `fop_read()` and `fop_write()` which accept pointers to `vnode_t` of file as their first argument and pointer to `uio` structure as their second argument (it describes user request and thus contains amount of data).
24 |
25 | Using all this we can get our `deblock.d` script:
26 |
27 | ````` scripts/dtrace/deblock.d
28 |
29 | We will trace SCSI stack by attaching to `scsi-transport-dispatch` probe which will receive pointer to `buf` as first argument. That is very similar to probes from `io` provider except that probe doesn't apply translators on buffer.
30 |
31 | Other changes in `readahead.d` are similar to those that was done for SystemTap:
32 |
33 | ````` scripts/dtrace/readahead.d
34 |
--------------------------------------------------------------------------------
/book/hints/ex6.md:
--------------------------------------------------------------------------------
1 | ### Exercise 6
2 |
3 | This exercise is not so different than any [latency measurement][principles/perf#latency] script where latency is measured as difference between timestamps of two probe firings and saved to an aggregation.
4 |
5 | Note that `plockstat$` provider doesn't serve a probe for mutex lock attempt, so we had to expand it by using `pid$` provider. As you may notice from ustack outputs in `pthread.d` example, mutex lock attempts are implemented by `mutex_lock_impl()` libc function. We will use `quantize()` aggregation which will be printed with `printa`:
6 |
7 | ````` scripts/dtrace/mtxtime.d
8 |
9 | You will need to bind this script to tsexperiment process using `-c` or `-p` option.
10 |
11 | We will need to use static probes `mutex_entry` and `mutex_acquired` for a SystemTap version of that script. However, we will need to be careful while working with userspace backtraces. First of all, we should use `-d` option to provide path to SystemTap for resolving symbols or `--ldd` to make it scan library dependencies of traced binary and automatically add them (when some of them are missing, `stap` utility will provide a hint with full paths).
12 |
13 | Mutexes are also often used in TSLoad which can cause excessive overheads when we try to trace them, especially when we will use `ubacktrace()` function. You can use `STP_NO_OVERLOAD` macro definition (which can be passed to `stap` with `-D` option) to prevent stap from failing when overheads are big, or you can reduce overheads. In our case we will limit amount of traced callers by using `ucallers()` function which accepts depth of backtrace as a first argument like `ustack()` function from backtrace and only collects addresses without resolving them to symbols. We will defer symbol resolving to an aggregation printing.
14 |
15 | Here are our script for SystemTap:
16 |
17 | ````` scripts/stap/mtxtime.stp
18 |
--------------------------------------------------------------------------------
/book/hints/ex7.md:
--------------------------------------------------------------------------------
1 | ### Exercise 7
2 |
3 | Nature of solution of this exercise depends on your Apache and PHP configuration. In our case (as described in [lab description][lab/web]), PHP was built as Apache HTTPD module (by using `--with-apxs2` option of `configure`-script), so all PHP code will be executed in a context of Apache worker, so we can safely use Thread-Local variables. If PHP was deployed with PHP-FPM, things would be more complicated.
4 |
5 | So we will need to use `process-request-entry` probe to get URI of request and pair of probes `function-entry`/`function-entry` to measure execution time of a function. Since name of a method is passed in multiple probe arguments, we will have to use string concatenation. Like in many other exercises, we will use aggregations to collect statistics. Note that you can use PHP probe `request-startup` instead of `process-request-entry`.
6 |
7 | As you could remember from a [profiling][principles/profiling] section of tracing principles, generally you shouldn't measure execution time of a function by tracing entry and exit points of it. However, PHP is an interpreted language, so it has lesser relative overheads of tracing because execution of its opcodes is slower than for the real processor (unless you are using some precompiler to machine language like HHVM) and we can afford full-tracing of it.
8 |
9 | Here are resulting implementations of scripts for SystemTap and DTrace:
10 |
11 | ````` scripts/stap/topphp.stp
12 | ````` scripts/dtrace/topphp.d
13 |
--------------------------------------------------------------------------------
/book/index.md:
--------------------------------------------------------------------------------
1 | [__endfrontpage__]
2 |
3 | Copyright © 2011-2016 Sergey Klyaus
4 |
5 | This work is licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 3.0 License. To view a copy of this license, visit [https://creativecommons.org/licenses/by-nc-sa/3.0/](https://creativecommons.org/licenses/by-nc-sa/3.0/) or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
6 |
7 | [__endbackpage__]
8 |
9 | Other formats: [PDF (cheatsheets)](dtrace-stap-cheatsheet.pdf), [PDF (full)](dtrace-stap-book.pdf), [PDF (no sources)](dtrace-stap-book-ns.pdf), [EPUB (no sources)](dtrace-stap-book.epub)
10 |
11 | ### Introduction
12 | [__docspace__:intro]
13 |
14 | * [Foreword][intro/foreword]
15 | * [Typographic conventions][intro/conv]
16 | * [TSLoad workload generator][intro/tsload]
17 | * [Operating system Kernel][intro/oskernel]
18 |
19 | ### Module 1: Dynamic tracing tools. dtrace and stap tools
20 | [__docspace__:tools]
21 |
22 | * [Tracing][tools/tracing]
23 | * [Dynamic tracing][tools/dyntrace]
24 | * [DTrace][tools/dtrace]
25 | * [SystemTap][tools/systemtap]
26 | * [Safety and errors][tools/safety]
27 | * [Stability][tools/stability]
28 |
29 | ### Module 2: Dynamic tracing languages
30 | [__docspace__:lang]
31 |
32 | * [Introduction][lang/intro]
33 | * [Probes][lang/probes]
34 | * [Arguments][lang/args]
35 | * [Context][lang/context]
36 | * [Predicates][lang/predicates]
37 | * [Types and Variables][lang/vars]
38 | * [Pointers][lang/pointers]
39 | * [Strings and Structures][lang/strstr]
40 | * [Exercise 1][lang/ex1]
41 | * [Associative arrays and aggregations][lang/assocarr]
42 | * [Time][lang/time]
43 | * [Printing and speculations][lang/print]
44 | * [Tapsets & translators][lang/tapset]
45 | * [Exercise 2][lang/ex2]
46 |
47 | ### Module 3: Principles of dynamic tracing
48 | [__docspace__:principles]
49 |
50 | * [Applying tracing][principles/apply]
51 | * [Dynamic code analysis][principles/dyncode]
52 | * [Profiling][principles/profiling]
53 | * [Performance analysis][principles/perf]
54 | * [Pre- and post-processing][principles/prepost]
55 | * [Vizualization][principles/viz]
56 |
57 | ### Module 4: Operating system kernel tracing
58 | [__docspace__:kernel]
59 |
60 | * [Process management][kernel/proc]
61 | * [Exercise 3][kernel/ex3]
62 | * [Process scheduler][kernel/sched]
63 | * [Virtual Memory][kernel/virtmem]
64 | * [Exercise 4][kernel/ex4]
65 | * [Virtual File System][kernel/fs]
66 | * [Block Input-Output][kernel/bio]
67 | * [Asynchronicity in kernel][kernel/async]
68 | * [Exercise 5][kernel/ex5]
69 | * [Network Stack][kernel/net]
70 | * [Synchronization primitives][kernel/sobj]
71 | * [Interrupt handling and deferred execution][kernel/irq]
72 |
73 | ### Module 5: Application tracing
74 | [__docspace__:app]
75 |
76 | * [Userspace process tracing][app/proc]
77 | * [Unix C library][app/libc]
78 | * [Exercise 6][app/ex6]
79 | * [Java Virtual Machine][app/java]
80 | * [Non-native languages][app/interp]
81 | * [Web applications][app/web]
82 | * [Exercise 7][app/ex7]
83 |
84 | ### Appendix A. Exercise hints and solutions
85 | [__docspace__:hints]
86 |
87 | * [Exercise 1][hints/ex1]
88 | * [Exercise 2][hints/ex2]
89 | * [Exercise 3][hints/ex3]
90 | * [Exercise 4][hints/ex4]
91 | * [Exercise 5][hints/ex5]
92 | * [Exercise 6][hints/ex6]
93 | * [Exercise 7][hints/ex7]
94 |
95 | ### Appendix B. Lab setup
96 | [__docspace__:lab]
97 |
98 | * [Setting up Operating Systems][lab/os]
99 | * [iSCSI][lab/iscsi]
100 | * [Web application stack][lab/web]
101 |
102 | ### Appendix C. [Cheatsheet][cheatsheet/cheatsheet]
103 | [__docspace__:cheatsheet]
104 |
--------------------------------------------------------------------------------
/book/intro/experiment.json:
--------------------------------------------------------------------------------
1 | { "name": "jump_table",
2 | "steps": {
3 | "jt": {
4 | "num_steps": 100,
5 | "num_requests": 2000 }
6 | },
7 | "threadpools": {
8 | "tp_jt" : {
9 | "num_threads": 24,
10 | "quantum": 2000000000,
11 | "disp": { "type": "round-robin" } }
12 | },
13 | "workloads" : {
14 | "jt" : {
15 | "wltype": "jt",
16 | "threadpool": "tp_jt",
17 | "params": {
18 | "num_request_types": 5000,
19 | "request_type": {
20 | "randgen": { "class": "lcg" } },
21 | "is_incorrect": {
22 | "randgen": { "class": "lcg" },
23 | "pmap": [
24 | { "probability": 0.2, "value": true },
25 | { "probability": 0.8, "value": false }
26 | ] } },
27 | "rqsched": {
28 | "type": "iat",
29 | "distribution": "exponential"
30 | }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/book/intro/oskernel.md:
--------------------------------------------------------------------------------
1 | ### Operating System Kernel
2 |
3 | !!! DEF
4 | According to Wikipedia, [Operating System Kernel](http://en.wikipedia.org/wiki/Kernel_%28operating_system%29) is
5 |
6 | > a computer program that manages I/O (input/output) requests from software, and translates them into data processing instructions for the central processing unit and other electron components of a computer. The kernel is a fundamental part of a modern computer's operating system.
7 |
8 | !!!
9 |
10 | We will refer to operating system kernel as _kernel_ in the rest of the book. Applications are using _system call_ mechanism to access various kernel functions, and by doing that they transfer control to kernel routines. The current state of application including all variables and current _program counter_ is called _context_. C is a programming language which is vastly used for writing Unix-like operating systems kernels such as Solaris, FreeBSD and Linux. C supports only procedural programming, but kernel developers adopted object-oriented and even functional programming.
11 |
12 | Where can we get information on kernel? Like I said, the most reliable source of such information is source codes which contain comments. You can use cross-reference tools to navigate source codes as easy as click a hyperlink. Some of them are publicly available: like [lxr.linux.no](http://lxr.linux.no/) which contains Linux source and [src.illumos.org](http://src.illumos.org/) which contains sources for Illumos (FOSS fork of OpenSolaris) in project illumos-gate. You can create your own cross-reference with OpenGrok tool: [https://github.com/OpenGrok/OpenGrok](https://github.com/OpenGrok/OpenGrok).
13 |
14 | Of course we have to mention textual sources of information. For Linux it is:
15 |
16 | * `Documentation/` directory in kernel sources
17 | * [Linux Kernel Mailing List](http://lkml.org/)
18 | * [Linux info from source](http://lwn.net/)
19 | * Robert Love book "Linux Kernel Development"
20 | * [Linux Device Drivers Book](https://lwn.net/Kernel/LDD3/)
21 |
22 | Some sources about Solaris:
23 |
24 | * [solaris.java.net](http://solaris.java.net/) -- remnants of old OpenSolaris site
25 | * Richard McDougall and Jim Mauro book "Solaris(TM) Internals: Solaris 10 and OpenSolaris Kernel Architecture"
26 | * Oracle course "Solaris 10 Operating System Internals"
27 |
28 | !!! WARN
29 | Solaris sources was closed after Oracle acquisition of Sun in 2009 and some information on Solaris may be outdated.
30 | !!!
31 |
--------------------------------------------------------------------------------
/book/intro/tsload.md:
--------------------------------------------------------------------------------
1 | ### [__index__:TSLoad workload generator] TSLoad workload generator
2 |
3 | During this course we will need to demonstrate created scripts on a real system. We will use version 0.2 of TSLoad workload generator to do so. Its [documentation](http://myaut.github.io/tsload/) and [source code](https://github.com/myaut/tsload) are available on GitHub.
4 |
5 | Experiment configuration files are kept in JSON format: each experiment starts with directory with `experiment.json` file in it (it can also be accompanied by traces and timeseries). This file contains description of threadpools and workloads: their types and parameters.
6 |
7 | ````` book/intro/experiment.json
8 |
9 | For example, [ref:experiment.json] defines an experiment called `jump_table`. `workloads` section defines workload `jt` which type is also `jt`. That workload have the following parameters:
10 |
11 | * `num_request_types` - set globally for entire workload - number of "request types" that will be generated;
12 | * `request_types` - generated for each request with linear congruential PRNG;
13 | * `is_incorrect` - boolean value which will be set to true for 20% requests.
14 |
15 | It also defines _request scheduler_ -- inter arrival time will be generated using exponential distribution. `steps` section defines number of requests which will be generated for this workload: 100 steps with 2000 requests in each.
16 |
17 | `threadpools` section defines threadpools which will perform our workloads. It defines pool `tp_jt` which contains 24 threads with step period set to 2 second (as paramter `quantum` sets in nanoseconds). _Threadpool dispatcher_ describes how requests will be distributed across threads and it is set to round-robin.
18 |
19 | If we try to draw a timing diagram of the requests generated by this configuration file we will get something like [image:tsload].
20 |
21 | 
22 |
23 | `jt` workload type is defined in a separate loadable module which contains code for simulating requests. During our book we meet similar modules in exercises: `proc_starter` which forks processes, `file_opener` which randomly opens files and other modules.
24 |
25 | Experiment is started with `tseexperiment` command:
26 | ```
27 | # tsexperiment -e /path/to/experiment run
28 | ```
29 |
30 | In this command `/path/to/experiment` is a directory which contains file `experiment.json`. That directory will also contain experiment results which can be listed with `list` subcommand of `tseexperiment`:
31 | ```
32 | # tsexperiment -e /path/to/experiment list
33 | ```
34 |
35 | Results may be exported to CSV format with `export` subcommand or some statistics may be shown with `report` subcommand.
36 |
37 | It is not necessary to edit configuration file each time parameter have to be altered: `run` subcommand has `-s` option. To provide its argument, check flattened names of configuration parameters with `-l` option of subcommand `show`:
38 | ```
39 | # tsexperiment -e /opt/tsload/var/tsload/mbench/jt show -l
40 | name=jump_table
41 | steps:jt:num_steps=100
42 | steps:jt:num_requests=2000
43 | ...
44 | ```
45 |
46 | So, to change number of per-step requests to 500, you should call `tsexperiment` with following options:
47 | ```
48 | # tsexperiment -e /opt/tsload/var/tsload/mbench/jt run \
49 | -s steps:jt:num_requests=500
50 | ```
51 |
52 | In some cases we will need to use hardware device names in experiment configuration, i.e. to bind threads to CPU cores. To get their names, run `tshostinfo` command:
53 | ```
54 | tshostinfo -x
55 | ```
--------------------------------------------------------------------------------
/book/kernel/ex3.md:
--------------------------------------------------------------------------------
1 | ### Exercise 3
2 |
3 | #### Part 1
4 |
5 | Modify `dumptask.stp` and `dumptask.d` so it will print information on successful binary load by `execve()` and before process exit. Write a simple program `lab3.c`:
6 |
7 | ````` scripts/src/lab3.c
8 |
9 | Compile it with GCC:
10 | ```
11 | # gcc lab3.c -o lab3
12 | ```
13 |
14 | Run changed scripts and run your program in different ways:
15 |
16 | * Run it with argument:
17 | ```
18 | # ./lab3 arg1
19 | ```
20 | * Create a symbolic link and run a program through it:
21 | ```
22 | # ln -s lab3 lab3-1
23 | # ./lab3-1
24 | ```
25 | * Created chrooted environment and run `lab3` inside it:
26 | ```
27 | # mkdir -p /tmp/chroot/bin /tmp/chroot/lib64 /tmp/chroot/lib
28 | # mount --bind /lib64 /tmp/chroot/lib64 (in Linux)
29 | # mount -F lofs /lib /tmp/chroot/lib (in Solaris)
30 | # cp lab3 /tmp/chroot/bin
31 | # chroot /tmp/chroot/ /bin/lab3
32 | ```
33 |
34 | __Q__: What data output has been changed? Try to explain these changes.
35 |
36 | #### Part 2
37 |
38 | Shell scripts have overhead caused by need to spawn new processes for basic operations, and thus calling `fork()` and `execve()`. Write SystemTap and DTrace scripts that measure following characteristics:
39 | * time, spent for `fork()` and `execve()` system calls;
40 | * time, spent for child process initialization in userspace: closing files and resetting signals -- it is time interval between finish of `fork()` call in child context and calling of `execve()`;
41 | * own program time after it was loaded with `execve()` and before it was exited.
42 |
43 | To be more correct, we should also measure time spent by `ld.so` loader and subtract it from _own program time_, but it involves complex tracing of userspace, so we leave it out of the scope of this exercise.
44 |
45 | Measure all time periods in microseconds and save them to an aggregations using process executable name and its program arguments.
46 |
47 | Use `proc_starter` experiment to demonstrate written script. This module starts `sh` shell (which can be overridden with `shell` parameter), uses `PS1` environment variable to reset prompt, and simulates real user entering commands by passing them through pseudo-terminal. Commands are represented as probability map `command`.
--------------------------------------------------------------------------------
/book/kernel/ex4.md:
--------------------------------------------------------------------------------
1 | ### Exercize 4
2 |
3 | #### Part 1
4 |
5 | Implement scripts `pfstat.d` and `pfstat.stp` which will print count of pagefaults grouping by a mmapped file name (if it reachable). Print statistics once per second. Use proc\_starter experiment from [exercize 3][kernel/ex3] to demonstrate it and try to explain results you are getting (you may need to include additional outputs for that).
6 |
7 | #### Part 2
8 |
9 | Implement scripts `kmemstatp.stp` and `kmemstat.d` which will gather stats on allocations and frees on per-cache basis for a _SLAB allocator_. Use an file\_opener experiment from [exercize 1][lang/ex1] to demonstrate your script and find a correlation between number of requests per-second generated by an experiment and cache allocations. What caches are primarily used while file is opened?
--------------------------------------------------------------------------------
/book/lab/iscsi.md:
--------------------------------------------------------------------------------
1 | ### iSCSI
2 |
3 | We will need to use SCSI device so we can fully trace it in [exercise 5][kernel/ex5]. Xen hypervisor supports SCSI emulation, but only by emulating outdated _LSI 53c895a_ controller which is not supported by Solaris. However, we can create iSCSI devices in Dom0 and supply them to virtual machines. The following guide is created for Debian 7 which uses _iSCSI Enterprise Target_. Recent Linux kernels replaced it with _LIO_ stack.
4 |
5 | * Install IET packages:
6 | ```
7 | # aptitude install iscsitarget iscsitarget-dkms
8 | ```
9 | * Create logical disks for virtual machines. They would be LVM volumes `/dev/mapper/vgmain-sol11--base--lab` and `/dev/mapper/vgmain-centos7--base--lab` in our example.
10 | * Create targets in `/etc/iet/ietd.conf` file by adding following lines:
11 | ```
12 | Target iqn.2154-04.tdc.r520:storage.lab5-sol11-base
13 | Lun 0 Path=/dev/mapper/vgmain-sol11--base--lab,Type=blockio
14 |
15 | Target iqn.2154-04.tdc.r520:storage.lab5-centos7-base
16 | Lun 0 Path=/dev/mapper/vgmain-centos7--base--lab,Type=blockio
17 | ```
18 | Note that target names should match DNS name of a host which provides them.
19 | * Configure `/etc/iet/initiators.allow` file to forbid Solaris access to disk allocated for CentOS machine and vice versa. Delete or comment out `ALL ALL` line and add lines with target names and IP addresses of corresponding machines:
20 | ```
21 | iqn.2154-04.tdc.r520:storage.lab5-sol11-base 192.168.50.179
22 | iqn.2154-04.tdc.r520:storage.lab5-centos7-base 192.168.50.171
23 | ```
24 | * Restart IET daemon:
25 | ```
26 | # /etc/init.d/iscsitarget restart
27 | ```
28 | * Configure Solaris initiator. `192.168.50.116` is an IP address of our Dom0 system which provides iSCSI targets.
29 | ```
30 | # iscsiadm add discovery-address 192.168.50.116
31 | # iscsiadm modify discovery -t enable
32 | # svcadm restart svc:/network/iscsi/initiator:default
33 | ```
34 | * Similarly configure CentOS initiator:
35 | ```
36 | # yum install iscsi-initiator-utils
37 | # systemctl enable iscsid
38 | # systemctl start iscsid
39 | # iscsiadm -m discovery -t sendtargets -p 192.168.50.116
40 | # iscsiadm -m node --login
41 | ```
42 |
--------------------------------------------------------------------------------
/book/lang/context.md:
--------------------------------------------------------------------------------
1 | ### [__index__:context of probe] [__index__:context function] Context
2 |
3 | !!! DEF
4 | _Probe context_ contains system state related to a fired probe, including:
5 | * Register values
6 | * Thread and process, which caused probe firing, including CPU where thread is running
7 | * Currently executing probe
8 | !!!
9 |
10 | Context is provided as built-in variables in DTrace such as `execname` or as tapset functions in SystemTap such as `execname()`.
11 |
12 | Userspace register values are available in DTrace through built-in variable `uregs`. In SystemTap, they available through Embedded C and kernel function `task_pt_regs`, or a special Embedded C variable `CONTEXT`, see for example implementation of `uaddr()` and `print_regs()` tapset functions.
13 |
14 | Here are some useful context information:
15 |
16 | ---
17 | _Description_ | _DTrace_ | _SystemTap_
18 | Current executing thread | `curthread` | `task_current()`
19 | ID of current thread | `tid` | `tid()`
20 | ID of current process | `pid` | `pid()`
21 | ID of parent of current process | `ppid` | `ppid()`
22 | User ID and group ID of current process | `uid`/`gid` | `uid()`/`gid()`, \
23 | `euid()`, `egid()`
24 | Name of current process executable | `execname` \
25 | `curpsinfo->ps_fname` | `execname()`
26 | Command Line Arguments | `curpsinfo->ps_psargs` | `cmdline_*()`
27 | CPU number | `cpu` | `cpu()`
28 | Probe names | `probeprov`, `probemod`, \
29 | `probefunc`, `probename` | `pp()`, `pn()`, `ppfunc()`, \
30 | `probefunc()`, `probemod()`
31 | ---
32 |
33 | #### References
34 |
35 | *  [Built-in Variables](http://docs.oracle.com/cd/E19253-01/817-6223/chp-variables/index.html#6mlkidlfu)
36 | *  [Context Functions](https://sourceware.org/systemtap/tapsets/context_stp.html)
--------------------------------------------------------------------------------
/book/lang/ex1.md:
--------------------------------------------------------------------------------
1 | ### Exercise 1
2 |
3 | Write `opentrace.d` and `opentrace.stp` scripts which are tracing `open()` system calls. They should print following information in one line:
4 | * Call context: name of executable file, process ID, user and group IDs of user and group which are executing process.
5 | * Path to file which should be opened.
6 | * A string containing `open()` flags `O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_APPEND`, `O_CREAT`
7 | * Return value of system call
8 |
9 | For example:
10 | ```
11 | tee[939(0:0)] open("/tmp/test", O_WRONLY|O_APPEND|O_CREAT) = 3
12 | ```
13 |
14 | Bit flags values are presented in following table:
15 |
16 | ---
17 | __Flag__ | __Solaris__ | __Linux (x86)__
18 | `O_RDONLY` |2,1 bits 0-1 are not set
19 | `O_WRONLY` | 1 | 1
20 | `O_RDWR` | 2 | 2
21 | `O_APPEND` | 8 | 1024
22 | `O_CREAT` | 256 |64
23 | ---
24 |
25 | Test script that your created by experimenting with redirection to file or a pipe with `tee` tool:
26 | ```
27 | # cat /etc/inittab > /tmp/test
28 | # cat /etc/inittab >> /tmp/test
29 | # cat /etc/inittab | tee /tmp/test
30 | # cat /etc/inittab | tee -a /tmp/test
31 | ```
32 |
33 | !!! WARN
34 | In Solaris 11 `open()` system call was replaced with more generic `openat()`.
35 | !!!
36 |
37 | _Optional_: Modify your scripts so only files that have "/etc" in their path will be shown.
--------------------------------------------------------------------------------
/book/lang/ex2.md:
--------------------------------------------------------------------------------
1 | ### Exercise 2
2 |
3 | Modify scripts from Exercise 1 so they count following statistics for processes that are running in a system:
4 | * number of attempts to open existing file;
5 | * number of attempts to create a file;
6 | * number of successful attempts.
7 |
8 | At a period that is defined as command line arguments (specified in seconds) script should print:
9 | * Current time and day in human-readable format.
10 | * Table that contains gathered statistics per process along with that process name and PID.
11 | Numbers should be cleared during each iteration.
12 |
13 | You can use module `file_opener` to demonstrate your scripts. This module uses working directory which is passed as `root_dir` parameter, fills it with some files that are created preliminary (their number is set by `created_files` parameter). While executing request, it uses `file` random variable (which range is cut to `[1;max_files)`) and either tries to create a file or open it depending on `create` parameter.
14 |
15 | Run several experiments using TSLoad workload generator varying `created_files` parameter and compare the results:
16 | ```
17 | # EXPDIR=/opt/tsload/var/tsload/file_opener
18 | # for I in 1 2 3; do
19 | mkdir /tmp/fopen$I
20 | tsexperiment -e $EXPDIR run \
21 | -s workloads:open:params:root_dir=/tmp/fopen$I \
22 | -s workloads:open:params:created_files=$((I * 160)) &
23 | done
24 | ```
25 |
26 | Try to explain differences you get from the nature of `file_opener` workload generator module.
--------------------------------------------------------------------------------
/book/lang/strstr.md:
--------------------------------------------------------------------------------
1 | ### [__index__:string operations] Strings
2 |
3 | Strings in dynamic tracing languages are wrappers around C-style null-terminated `char*` string, but they behave differently. In SystemTap it is simple alias, while DTrace add extra limitations, for example, you can't access single character to a string. String operations are listed in following table:
4 |
5 | ---
6 | __Operation__ | __DTrace__ | __SystemTap__
7 | Get kernel string |1,2 `stringof ( expr )` or \
8 | `(string) expr` | `kernel_string*()`
9 | Convert a scalar type to a string | `sprint()` and `sprintf()`
10 | Get userspace string | `copyinstr()` | `user_string*()`
11 | Compare strings |2,1 `==`, `!=`, `>`, `>=`, `<`, `<=` -- semantically equivalent to `strcmp`
12 | Concatenate two strings | `strjoin(str1, str2)` | `str1 . str2`
13 | Get string length |2,1 `strlen(str)`
14 | Check if substring is in string | `strstr(haystack, needle)` | `isinstr(haystack, needle)`
15 | ---
16 |
17 | Note that this operations may be used in DTrace predicates, for example:
18 | ```
19 | syscall::write:entry
20 | /strstr(execname, "sh") != 0/
21 | {}
22 | ```
23 |
24 | #### References
25 |
26 | *  [Strings](http://docs.oracle.com/cd/E19253-01/817-6223/chp-strings/index.html)
27 | *  [Actions and Subroutines](http://docs.oracle.com/cd/E19253-01/817-6223/chp-actsub/index.html)
28 | *  [Strings](https://sourceware.org/systemtap/langref/Language_elements.html#SECTION00062300000000000000)
29 | *  [A collection of standard string functions](https://sourceware.org/systemtap/tapsets/string.stp.html)
30 |
31 | ### [__index__:structure field access] Structures
32 |
33 | Many subsystems in Linux and Solaris have to represent their data as C structures. For example, path to file corresponds from file-related structure `dentry` and filesystem-related structure `vfsmnt`:
34 | ```
35 | struct path {
36 | struct vfsmount *mnt;
37 | struct dentry *dentry;
38 | };
39 | ```
40 |
41 | Structure fields are accessed same way it is done in C: in DTrace depending on what you are getting you need to use `->` for pointers and `.` for structures. In SystemTap you should always use `->` which will be contextually converted to `.` where needed. Information about structures is read from CTF sections in Solaris and DWARF sections in Linux, including field names. To get C structure you may need to cast a generic pointer (`void*` in most cases) to a needed structures. In DTrace it is done using C-style syntax:
42 | ```
43 | (struct vnode *)((vfs_t *)this->vfsp)->vfs_vnodecovered
44 | ```
45 |
46 | Conversion in SystemTap is used more often, because in many places, typed pointers are coerced to generic `long` type. It is performed with `@cast` expression which accepts address, name of structure as string (`struct` keyword is optional), and an optional third parameter which contains name of include file, for example:
47 | ```
48 | function get_netdev_name:string (addr:long) {
49 | return kernel_string(@cast(addr, "net_device")->name)
50 | }
51 | ```
52 |
53 | #### References
54 |
55 | *  [Structs and Unions](http://docs.oracle.com/cd/E19253-01/817-6223/chp-structs/index.html)
56 | *  [Expressions](https://sourceware.org/systemtap/langref/Language_elements.html#SECTION000661000000000000000)
--------------------------------------------------------------------------------
/book/lang/tapset.md:
--------------------------------------------------------------------------------
1 | ### Tapsets & translators
2 |
3 | We already discussed problem with probe stability. Some issues may be related to changing data structures in kernel, or several variants may exist in kernel, for example for 32- and 64-bit calls. Let's see how access to fields of that structure may be unified.
4 |
5 | [__index__:translators (DTrace)] DTrace has a _translators_ for doing that:
6 |
7 | ````` scripts/dtrace/stat.d
8 |
9 | In this example translator describes rules of converting source structure `stat64_32` to a structure with known format defined in DTrace `stat_info`. After that, `xlate` operator is called which receives pointer to `stat64_32` structure to a `stat_info`. Note that our translator also responsible for copying data from userspace to kernel. Built-in DTrace translators are located in `/usr/lib/dtrace`.
10 |
11 | [__index__:tapset] [__index__:prologue probe alias] [__index__:epilogue probe alias] SystemTap doesn't have translators, but you can create _prologue_ or _epilogue alias_ which performs necessary conversions before (or after, respectively) probe is called. These aliases are grouped into script libraries called _tapsets_ and put into `/usr/share/systemtap/tapset` directory. Many probes that we will use in following modules are implemented in such tapsets.
12 |
13 | Linux has several variants for `stat` structure in `stat()` system call, some of them deprecated, some are intended to support 64-bit sizes for 32-bit callers. By using following tapset we will remove such differences and make them universally available through `filename` and `size` variables:
14 |
15 | ````` scripts/stap/tapset/lstat.stp
16 |
17 | This example is unrealistic: it is easier to attach to `vfs_lstat` function which has universal representation of `stat` structure and doesn't involve copying from userspace. Summarizing the syntax of creating aliases:
18 | ```
19 | probe alias-name {=|+=} probe-name-1 [?] [,probe-name-2 [?] ...] probe-body
20 | ```
21 | Here `=` is used for creating prologue aliases and `+=` is for epilogue aliases. Question mark `?` suffix is optional and used if some functions are not present in kernel -- it allows to choose probe from multiple possibilities.
22 |
23 | !!! WARN
24 | Note that this tapset only checks for 64-bit Intel architecture. You will need additional checks for PowerPC, AArch64 and S/390 architectures.
25 | !!!
26 |
27 | After we created this tapset, it can be used very easy:
28 |
29 | ````` scripts/stap/lstat.stp
30 |
31 | Also, sometimes we have to define constants in dynamic tracing scripts that match corresponding kernel or application constants. You can use enumerations for that in DTrace, or define a constant variable with `inline` keyword:
32 | ```
33 | inline int TS_RUN = 2;
34 | ```
35 | You may use initializer for global variable to do that in SystemTap:
36 | ```
37 | global TASK_RUNNING = 0;
38 | ```
39 | If you have enabled preprocessor with `-C` option, you may use `#define` to create macro as well.
40 |
41 | #### References
42 |
43 | *  [Translators](http://docs.oracle.com/cd/E19253-01/817-6223/chp-xlate/index.html)
44 | *  [Probe aliases](https://sourceware.org/systemtap/langref/Components_SystemTap_script.html#SECTION00042000000000000000)
--------------------------------------------------------------------------------
/book/lang/time.md:
--------------------------------------------------------------------------------
1 | ### [__index__:monotonic time] [__index__:wall-clock time] Time
2 |
3 | A man used to live with a calendar and 24-hour representation of time. Coordinated Universal Time (UTC) is used for that now. These details are not needed for most kernel or application processes, so there is multiple time sources available for tracing tools:
4 |
5 | --- %60,20,20
6 | __Time source__ | __DTrace__ | __SystemTap__
7 | _System timer_ is responsible for handling periodical events in kernel such as context switch. System timer usually ticks at constant frequency (but ticks may be omitted in _tickless kernels_). Interval between firing timer is usually referred as special unit of time: _tick_, _lbolt_ in Solaris or _jiffy_ in Linux. Timer frequency in Linux can be get using `HZ()` function. | `\`lbolt` or `\`lbolt64` | `jiffies()`
8 | _Processor cycles counter_ is a special CPU register which act as a counter which increases on each cycle, such as `TSC` in x86 or `%tick` in SPARC. It may not be monotonic. | | `get_cycles()`
9 | _Monotonic time_. Starts at unspecified moment of time (usually at system boot), but ticks with constant intervals. May use high-resolution time source such as HPET on x86, but may impose some jitter between CPU cores or CPUs. | `timestamp` | `local_clock_()` or `cpu_clock_()`
10 | _Virtual monotonic time of thread_. Similar to previous time source, but only accounts when thread is on CPU, which is useful to calculate CPU usage of a thread | `vtimestamp` |
11 | _Real time_ or _Wall-clock time_. Monotonic time source which starting point is an UNIX Epoch (00:00:00 UTC, Thursday, 1 January 1970). May use extra locks, access RTC, so it generally slower than previous time sources | `walltimestamp` | `gettimeofday_()`
12 | ---
13 |
14 | In this examples `` is one of (`s` -- seconds, `ms` -- milliseconds, `us` -- microseconds and `ns` -- nanoseconds). DTrace time sources always have nanosecond resolution.
15 |
16 | Generally speaking, monotonic time sources are better for measurement relative time intervals, while real time is used if you need precise timestamp of an event (i.e. for cross-referencing with logs). To print a real timestamp, use `ctime()` function in SystemTap which converts time to string, or use `%Y` format specifier in DTrace print functions.
17 |
18 | #### References
19 |
20 | *  [Built-in Variables](http://docs.oracle.com/cd/E19253-01/817-6223/chp-variables/index.html#6mlkidlfu)
21 | *  [Timestamp Functions](https://sourceware.org/systemtap/tapsets/timestamp_stp.html)
--------------------------------------------------------------------------------
/book/principles/apply.md:
--------------------------------------------------------------------------------
1 | ### Applying tracing
2 |
3 | As we mentioned in [Tracing][tools/tracing], it is used for statistics collection and performance analysis, dynamic kernel or application debug, system audit. Imagine the situation in which various processes running by two different users are opening files:
4 |
5 | 
6 |
7 | What problems can occur and how they are solved by dynamic tracing? Users can complain to very slow opening of a file, so we need to do _performance analysis_. First of all, we have confirm user complaints by measuring time spent in `open()`, `read()` and `write()` system calls. We can also try to cross-reference slow calls and filesystems on which they occur (by gathering mount paths), if problems are caused by bad NAS or disk. If the problem still exists, than you will need to go down VFS stack, i.e. by measuring time spent in block I/O or in lookup operations.
8 |
9 | If user encounters errors while opening files, then you will need to trace `errno` values. These values are usually returned by system call functions in Linux, or saved into `errno` variable in DTrace. To determine why system call returns an error, you will need _dynamically debug_ it by checking return values of callees. We will demonstrate it in following section. If users try to attempt files they do not have permissions, we can record `errno` along with paths and user ids, so by doing that we will perform _system audit_.
10 |
11 | To demonstrate it on real example, we will use following examples and run `cat /etc/shadow` from some non-root user:
12 | ```
13 | # dtrace -qn '
14 | syscall::open*:entry {
15 | printf("=> uid: %d pid: %d open: %s %lld\n",
16 | uid, pid, copyinstr(arg1), (long long) timestamp);
17 | }
18 | syscall::open*:return {
19 | printf("<= uid: %d pid: %d ret: %d %lld\n",
20 | uid, pid, arg1, (long long) timestamp);
21 | }'
22 | ```
23 |
24 | SystemTap version:
25 | ```
26 | # stap -e '
27 | probe syscall.open {
28 | printf("=> uid: %d pid: %d open: %s %d\n",
29 | uid(), pid(), filename, local_clock_ns());
30 | }
31 | probe syscall.open.return {
32 | printf("<= uid: %d pid: %d %d %d\n",
33 | uid(), pid(), $return, local_clock_ns());
34 | }'
35 | ```
36 |
37 | Here is sample output:
38 | ```
39 | => uid: 60004 pid: 1456 open: /etc/shadow 16208212467213
40 | <= uid: 60004 pid: 1456 ret: -1 16208212482430
41 | ```
42 |
43 | First of all, we measured time spent for `open()` system call: `16208212482430 — 16208212467213 = 15217 = 15.2 us`. We can also see that user received an error (return code is `-1`, while in case of correct call it would be positive) and now we may try to seek for a source of a problem. Finally, we have audited attempt to open critical system file `/etc/shadow` which is forbidden for users. So now we should find user name with id 60004 and politely ask him why he tried to open `/etc/shadow` file.
44 |
45 | We will discuss how trace data may be analysed and what conclusion can be made from it in this module. However, we will not introduce useful kernel or application probes as we will discuss them in modules 4, 5. On the other hand, all examples in following modules will be pure tracers, so you will need to add additional processing of results which will be discussed in this module.
46 |
--------------------------------------------------------------------------------
/book/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | $TITLE
9 |
10 |
11 |
12 |
13 |
24 |
25 |
34 |
35 |
36 |
37 | $HEADER
38 |
39 |
40 |
41 |
42 | $NAVBAR_TOP
43 |
44 |
45 |
46 |
47 |
48 |
49 | $BODY
50 |
51 |
52 |
53 | $TAIL
54 |
55 |
56 |
57 |
58 | $NAVBAR_BOTTOM
59 |
60 |
61 |
62 |
63 |
72 |
73 |
--------------------------------------------------------------------------------
/book/tools/stability.md:
--------------------------------------------------------------------------------
1 | ### Stability
2 |
3 | Another problem to which dynamic tracing systems face is stability of in-kernel interfaces. While system calls never change their interface due to backwards compatibility (if something need to be changed, new system call is introduced†), internal kernel function often do that especially if they not a public API for a drivers. Dynamic tracing languages provide mechanisms to avoid direct use of in-kernel interface by hiding them in abstractions:
4 |
5 | ---
6 | 1,2 _Stability_ |2,1 __Data access__
7 | _DTrace_ | _SystemTap_
8 | High | _translators_, i.e. `fileinfo_t` | tapset variables
9 | Lowest | Global variables and raw arguments like `args[0]` or `(struct_t*) arg0` | Raw arguments like `$task` or `@cast($task, "task_struct")`
10 | ---
11 |
12 | ---
13 | 1,2 _Stability_ |2,1 __Tracepoints__
14 | _DTrace_ | _SystemTap_
15 | High | statically defined tracing providers (like `io` and many others) | tapset aliases, i.e. `vm.kfree`
16 | Mediocre | static tracepoints with `sdt` provider | statically defined ftrace probes like `kernel.trace("kfree")`
17 | Lowest | `fbt` and `pid$$` providers | DWARF probes like `kernel.function("kfree")`
18 | ---
19 |
20 | [__index__:tapset]
21 | To achieve maximum script portability, you should pick highest stability options wherever possible. Downside of that approach is that it provides fewer information than you could access with other approaches. These options will be described in [Translators and tapsets][lang/tapset] section of next module.
22 |
23 | [__index__:conditional compilation]
24 | Linux kernel is changing faster: it has stable releases each 2-3 months, and moreover, its builds are configurable, so some features present in one kernel may be disabled in another and vice versa which makes stability is much more fragile. To overcome that, SystemTap Language has conditional compilation statements which like in C allow to disable certain paths in code. Simplest conditional compilation statements are `@defined` which evaluates to true if variable passed to it is present in debug information and `@choose_defined` which chooses from several variables. It also support ternary conditional expression:
25 | ```
26 | %( kernel_v >= "2.6.30"
27 | %? count = kernel_long($cnt)
28 | %: count = $cnt
29 | %)
30 | ```
31 |
32 | Here, `kernel_v` is numerical version of kernel without suffix (for version with suffix, use `kernel_vr`). SystemTap also defines `arch` variable and `CONFIG_*` tokens similiar to configuration options. These options are not available in Embedded C, use traditional preprocessor there.
33 |
34 | [__index__:missing probe]
35 | Finally, if some probe is missing from kernel, script compilation will fail. DTrace allow to ignore such errors by passing `-Z` command line option. In SystemTap you may add `?` at the end of probe name to make this probe optional.
36 |
37 | #### Notes
38 |
39 | † -- unless you are running Solaris 11 which was deprecated and obsoleted many of its system calls..
40 |
41 | #### References
42 |
43 | *  [Conditional compilation](https://sourceware.org/systemtap/langref/Language_elements.html#SECTION00068000000000000000)
44 | *  [Stability](http://docs.oracle.com/cd/E19253-01/817-6223/chp-stab/index.html)
45 |
--------------------------------------------------------------------------------
/book/tools/tracing.md:
--------------------------------------------------------------------------------
1 | ### Tracing
2 |
3 | Operating system and application are crucial parts of a computer system, but due to their colossal complexity, there are situations related to software bugs, incorrect system setup that lead to incorrect behavior. To address these issues, system administrator should perform _instrumentation_ which depends on the issue arisen: it could be performance statistics collection and their analysis, debug or system audit. Two common approaches to _instrumentation_ are _sampling_ when you collect state of the system: values of some variables, stacks of threads, etc. at unspecified moments of time and _tracing_ when you install probes at specified places of software. _Profiling_ is a most famous example of _sampling_.
4 |
5 | _Sampling_ is very helpful when you do not know where issue happens, but it hardly help when you try to know why it happened. I.e. profiling revealed that some function, say `foo()` that processes lists of elements, consumes 80% of the time, but doesn't say why: whether some lists are too long, or they should be pre-sorted, or list is inappropriate data structure for `foo()`, or whatever. With _tracing_ we can install a probe to that function, gather information on lists (say their length) and collect cumulative execution of function `foo()`, and then cross-reference them, searching for a pattern in lists whose processing costs too much CPU time.
6 |
7 | Over time operating system kernels have grown different methods of tracing. First one and a simplest one is __counters__ -- each time probe fires (say, major page fault), they increase some counter. Counters may be read through kstat interface in Solaris:
8 | ```
9 | # kstat -p |grep maj_fault
10 | cpu:0:vm:maj_fault 7588
11 | ```
12 |
13 | Linux usually provides counters through `procfs` or `sysfs`:
14 | ```
15 | # cat /proc/vmstat | grep pgmajfault
16 | pgmajfault 489268
17 | ```
18 |
19 | This approach is limited: you can't add counter for every event without losing performance, and they are usually system-wide (i.e. you can't know what process causing major-faults), or process/thread-wide.
20 |
21 | More complex approach is __debug printing__: add a `printk()` or `cmn_err()` statement as a probe, but this approach is quite limited, because you need recompile kernel each time you need new set of probes. But if all debug printing will be enabled, you will get excessive system load. By default, most of debug printing in Solaris are disabled unless you compile a DEBUG-build, which is not publicly available. Modern Linux kernels however developed a dynamic debugging facility available via `pr_debug()`. There are several __static probes__ which are deactivated on systems start, but can be activated externally: _ftrace_ and _kprobes_ in Linux and _TNF_ on Solaris, but amount of information provided by them is still limited, and _ftrace_/_kprobes_ are requiring writing kernel modules which is not convenient and dangerous.
22 |
23 | So, generally speaking, that approaches provide very limited set of data at very limited set of tracing points. The only approach that widens that limits is __kernel debugger__, but because each breakpoint halts system, __it cannot be used on production systems__. The answer to them are __dynamic tracing__ which is the topic of this book.
24 |
--------------------------------------------------------------------------------
/book/watermark.txt:
--------------------------------------------------------------------------------
1 | This cheatsheet is based on
2 | Dynamic Tracing with DTrace & SystemTap
3 | book by Sergey Klyaus
4 | This work is licensed under the (CC BY-NC-SA 3.0) License.
--------------------------------------------------------------------------------
/experiments/concurrency/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "concurrency",
3 | "steps": {
4 | "worker": {
5 | "num_steps": 20,
6 | "num_requests": 40,
7 | }
8 | },
9 | "threadpools": {
10 | "tp_worker": {
11 | "num_threads": 2,
12 | "quantum": 1000000000,
13 | "disp": {
14 | "type": "benchmark"
15 | },
16 | "sched" : [
17 | { "wid": "all",
18 | "objects": ["strand:0:0:0"] }
19 | ]
20 | }
21 | },
22 | "workloads" : {
23 | "worker": {
24 | "wltype": "busy_wait",
25 | "threadpool": "tp_worker",
26 | "rqsched": { "type": "simple" },
27 | "params": { "num_cycles": 4000000 }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/experiments/deblock/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "deblock",
3 | "steps": {
4 | "fileio": {
5 | "num_steps": 20,
6 | "num_requests": 80
7 | }
8 | },
9 | "threadpools": {
10 | "tp_fileio": {
11 | "num_threads": 4,
12 | "quantum": 1000000000,
13 | "disp": { "type": "round-robin" }
14 | }
15 | },
16 | "workloads": {
17 | "fileio": {
18 | "wltype": "fileio",
19 | "threadpool": "tp_fileio",
20 | "rqsched": { "type": "iat", "distribution": "exponential" },
21 | "params": {
22 | "path": "/tiger/DEBLOCK",
23 | "file_size": 1048576,
24 | "sync": true,
25 | "rw": "write",
26 | "block_size": {
27 | "randgen": { "class": "lcg" },
28 | "randvar": { "class": "uniform",
29 | "min": 512,
30 | "max": 16384 }
31 | },
32 | "offset": { "randgen": { "class": "lcg" } }
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/experiments/drupal/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "drupal",
3 | "steps": {
4 | "drupal": {
5 | "num_steps": 10,
6 | "num_requests": 14
7 | }
8 | },
9 | "threadpools": {
10 | "drupal_users" : {
11 | "num_threads": 8,
12 | "quantum": 4000000000,
13 | "disp": {
14 | "type": "user"
15 | }
16 | }
17 | },
18 | "workloads" : {
19 | "drupal" : {
20 | "wltype": "http",
21 | "threadpool": "drupal_users",
22 | "rqsched": {
23 | "type": "think",
24 | "nusers": 8,
25 | "distribution": "exponential"
26 | },
27 | "params": {
28 | "server": "localhost",
29 | "port": 80,
30 | "uri": {
31 | "randgen": { "class" : "lcg" },
32 | "pmap" : [
33 | {
34 | "value": "/drupal/",
35 | "probability": 0.4
36 | },
37 | {
38 | "value": "/drupal/?q=node&page=1",
39 | "probability": 0.3
40 | },
41 | {
42 | "valarray":
43 | [ "/drupal/?q=node/1",
44 | "/drupal/?q=node/2",
45 | "/drupal/?q=node/3",
46 | "/drupal/?q=node/4",
47 | "/drupal/?q=node/5",
48 | "/drupal/?q=node/6",
49 | "/drupal/?q=node/7",
50 | "/drupal/?q=node/8",
51 | "/drupal/?q=node/9",
52 | "/drupal/?q=node/10",
53 | "/drupal/?q=node/11",
54 | "/drupal/?q=node/12",
55 | "/drupal/?q=node/13",
56 | "/drupal/?q=node/14",
57 | "/drupal/?q=node/15",
58 | "/drupal/?q=node/16",
59 | "/drupal/?q=node/17",
60 | "/drupal/?q=node/18",
61 | "/drupal/?q=node/19",
62 | "/drupal/?q=node/20",
63 | "/drupal/?q=node/21",
64 | "/drupal/?q=node/22",
65 | "/drupal/?q=node/23",
66 | "/drupal/?q=node/24",
67 | "/drupal/?q=node/25",
68 | "/drupal/?q=node/26",
69 | "/drupal/?q=node/27",
70 | "/drupal/?q=node/28",
71 | "/drupal/?q=node/29",
72 | "/drupal/?q=node/30",
73 | "/drupal/?q=node/31",
74 | "/drupal/?q=node/32",
75 | "/drupal/?q=node/33",
76 | "/drupal/?q=node/34",
77 | "/drupal/?q=node/35",
78 | "/drupal/?q=node/36",
79 | "/drupal/?q=node/37",
80 | "/drupal/?q=node/38",
81 | "/drupal/?q=node/39",
82 | "/drupal/?q=node/40",
83 | "/drupal/?q=node/41",
84 | "/drupal/?q=node/42",
85 | "/drupal/?q=node/43",
86 | "/drupal/?q=node/44",
87 | "/drupal/?q=node/45",
88 | "/drupal/?q=node/46",
89 | "/drupal/?q=node/47",
90 | "/drupal/?q=node/48",
91 | "/drupal/?q=node/49",
92 | "/drupal/?q=node/50"
93 | ],
94 | "probability": 0.3
95 | }
96 | ]
97 | }
98 | }
99 | },
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/experiments/duality/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "duality",
3 | "steps": {
4 | "manager": {
5 | "num_steps": 20,
6 | "num_requests": 20,
7 | },
8 | "worker": {
9 | "num_steps": 20,
10 | "num_requests": 20,
11 | }
12 | },
13 | "threadpools": {
14 | "tp_manager": {
15 | "num_threads": 1,
16 | "quantum": 1000000000,
17 | "disp": {
18 | "type": "round-robin"
19 | },
20 | "sched" : [
21 | { "wid": 0,
22 | "objects": ["strand:0:0:0"] }
23 | ]
24 | },
25 | "tp_worker": {
26 | "num_threads": 1,
27 | "quantum": 1000000000,
28 | "disp": {
29 | "type": "benchmark"
30 | },
31 | "sched" : [
32 | { "wid": 0,
33 | "objects": ["strand:0:0:0"] }
34 | ]
35 | }
36 | },
37 | "workloads" : {
38 | "manager": {
39 | "wltype": "busy_wait",
40 | "threadpool": "tp_manager",
41 | "rqsched": {
42 | "type": "iat",
43 | "distribution": "exponential"
44 | },
45 | "params": { "num_cycles": 800000 }
46 | },
47 | "worker": {
48 | "wltype": "busy_wait",
49 | "threadpool": "tp_worker",
50 | "rqsched": { "type": "simple" },
51 | "params": { "num_cycles": 4000000 }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/experiments/pthread/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pthread",
3 | "steps": {
4 | "busy": {
5 | "num_steps": 20,
6 | "num_requests": 1000
7 | }
8 | },
9 | "threadpools": {
10 | "busy_tp" : {
11 | "num_threads": 2,
12 | "quantum": 1000000000,
13 | "disp": {
14 | "type": "round-robin"
15 | }
16 | }
17 | },
18 | "workloads" : {
19 | "busy" : {
20 | "wltype": "busy_wait",
21 | "threadpool": "busy_tp",
22 | "rqsched": {
23 | "type": "iat",
24 | "distribution": "exponential"
25 | },
26 | "params": {
27 | "num_cycles": 100000
28 | }
29 | },
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/experiments/readahead/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "readahead",
3 | "steps": {
4 | "fileio": {
5 | "num_steps": 20,
6 | "num_requests": 80
7 | }
8 | },
9 | "threadpools": {
10 | "tp_fileio": {
11 | "num_threads": 4,
12 | "quantum": 1000000000,
13 | "disp": { "type": "round-robin" }
14 | }
15 | },
16 | "workloads": {
17 | "fileio": {
18 | "wltype": "fileio",
19 | "threadpool": "tp_fileio",
20 | "rqsched": { "type": "iat", "distribution": "exponential" },
21 | "params": {
22 | "path": "/tiger/READAHEAD",
23 | "file_size": 20971520,
24 | "overwrite": true,
25 | "sync": false,
26 | "rw": "read",
27 | "block_size": 512,
28 | "offset": { "randgen": { "class": "seq" } }
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/fonts/DejaVuSansMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/fonts/DejaVuSansMono-Bold.ttf
--------------------------------------------------------------------------------
/fonts/DejaVuSansMono-BoldOblique.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/fonts/DejaVuSansMono-BoldOblique.ttf
--------------------------------------------------------------------------------
/fonts/DejaVuSansMono-Oblique.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/fonts/DejaVuSansMono-Oblique.ttf
--------------------------------------------------------------------------------
/fonts/DejaVuSansMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/fonts/DejaVuSansMono.ttf
--------------------------------------------------------------------------------
/fonts/lcmss8.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/fonts/lcmss8.pfb
--------------------------------------------------------------------------------
/images/SConscript:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from itertools import chain
5 |
6 | Import('env')
7 |
8 | def _inkscape_builder(opt, suffix):
9 | return Builder(action = Action('inkscape -z %s $TARGET $SOURCE' % opt),
10 | suffix = suffix, src_suffix = '.svg')
11 |
12 | InkscapeBuilder = _inkscape_builder('-e', '.svg.png')
13 | InkscapeSVGBuilder = _inkscape_builder('-l', '.plain.svg')
14 | InkscapePDFBuilder = _inkscape_builder('-A', '.pdf')
15 |
16 | CompressBuilder = Builder(action = Action('convert -define png:compression-level=9 -define png:compression-strategy=0 -define png:compression-filter=0 $SOURCE $TARGET'),
17 | suffix = '.png',
18 | src_suffix = '.svg.png')
19 | SVGMerger = Builder(action = Action('%s images/merge-svgs.py $TARGET $SOURCES' % (sys.executable)),
20 | src_suffix = '.svg', suffix = '.svg')
21 |
22 |
23 | env.Append(BUILDERS = {'InkscapeBuilder': InkscapeBuilder,
24 | 'InkscapeSVGBuilder': InkscapeSVGBuilder,
25 | 'InkscapePDFBuilder': InkscapePDFBuilder,
26 | 'SVGMerger': SVGMerger,
27 | 'CompressBuilder': CompressBuilder})
28 |
29 |
30 | def ConvertSVGs(env, imgdir, width):
31 | img = env.Clone()
32 | img['PNGWIDTH'] = width
33 |
34 | tgt = []
35 |
36 | for image in imgdir.glob('*.svg'):
37 | if image.abspath.endswith('plain.svg'):
38 | continue
39 |
40 | img.CompressBuilder(None, img.InkscapeBuilder(None, image))
41 | img.InkscapeSVGBuilder(None, image)
42 | img.InkscapePDFBuilder(None, image)
43 |
44 | for image in chain(imgdir.glob('*.png'), imgdir.glob('*.plain.svg'), imgdir.glob('*.pdf')):
45 | env.Depends('images', tgt)
46 |
47 | env.SVGMerger('netprobes2.svg', ['netprobes.svg', 'net.svg'])
48 |
49 | ConvertSVGs(env, Dir('.'), 800)
50 | ConvertSVGs(env, Dir('linux'), 800)
51 | ConvertSVGs(env, Dir('solaris'), 800)
52 | ConvertSVGs(env, Dir('conv'), 300)
53 | ConvertSVGs(env, Dir('icons'), 24)
--------------------------------------------------------------------------------
/images/density.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/images/density.png
--------------------------------------------------------------------------------
/images/heatmap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/images/heatmap.png
--------------------------------------------------------------------------------
/images/linear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/images/linear.png
--------------------------------------------------------------------------------
/images/merge-svgs.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import xml.etree.ElementTree as etree
5 |
6 | NAMESPACES = {
7 | '': 'http://www.w3.org/2000/svg',
8 | 'xlink': 'http://www.w3.org/1999/xlink',
9 | 'sodipodi': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
10 | 'inkscape': 'http://www.inkscape.org/namespaces/inkscape'
11 | }
12 |
13 | def _xml_tag(tag, ns=''):
14 | return '{{{0}}}{1}'.format(NAMESPACES[ns], tag)
15 |
16 | # Parse args and process
17 | target = sys.argv[1]
18 | source = sys.argv[2]
19 | extrasvgs = dict((os.path.basename(fname), fname)
20 | for fname in sys.argv[3:])
21 |
22 | for ns, uri in NAMESPACES.items():
23 | etree.register_namespace(ns, uri)
24 |
25 | # Parse main image
26 | tree = etree.parse(source)
27 | root = tree.getroot()
28 |
29 | for group in root.findall('.//' + _xml_tag('g')):
30 | use = group.find(_xml_tag('use'))
31 | if use is None:
32 | continue
33 |
34 | href = use.attrib[_xml_tag('href', 'xlink')]
35 |
36 | if href not in extrasvgs:
37 | raise ValueError('Invalid use reference {0}'.format(href))
38 |
39 | group.clear()
40 |
41 | # Read sub svg
42 | extrasvg = etree.parse(extrasvgs[href]).getroot()
43 | extragroup = extrasvg.find(_xml_tag('g'))
44 | if extragroup is not None:
45 | group.extend(extragroup)
46 |
47 | tree.write(target)
--------------------------------------------------------------------------------
/images/oncpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/myaut/dtrace-stap-book/92f30d688f4caec1c17e702ec1e886687a0111f1/images/oncpu.png
--------------------------------------------------------------------------------
/scripts/dtrace/callgraph.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -s
2 |
3 | #pragma D option flowindent
4 |
5 | syscall::open*:entry
6 | /pid == $target && copyinstr(arg0) == "not_exists"/
7 | {
8 | self->traceme = 1;
9 | }
10 |
11 | syscall::open*:return
12 | /self->traceme/
13 | {
14 | self->traceme = 0;
15 | }
16 |
17 | fbt:::entry
18 | /self->traceme && probefunc != "bcmp"/
19 | {
20 |
21 | }
22 |
23 | fbt:::return
24 | /self->traceme && probefunc != "bcmp"/
25 | {
26 | trace(arg1);
27 | }
28 |
--------------------------------------------------------------------------------
/scripts/dtrace/cvtrace.d:
--------------------------------------------------------------------------------
1 | cv_wait*:entry {
2 | self->timeout = 0;
3 | }
4 |
5 | cv_timedwait_hires:entry,
6 | cv_timedwait_sig_hires:entry {
7 | self->timeout = (arg2 / arg3) * arg3;
8 | }
9 |
10 | cv_wait:entry,
11 | cv_wait_sig:entry,
12 | cv_wait_sig_swap_core:entry,
13 | cv_timedwait_hires:entry,
14 | cv_timedwait_sig_hires:entry {
15 | printf("[%d] %s %s cv: %p mutex: %p timeout: %d\n",
16 | pid, execname, probefunc, arg0, arg1, self->timeout);
17 | stack(4);
18 | }
19 |
20 | cv_signal:entry,
21 | cv_broadcast:entry {
22 | printf("[%d] %s %s cv: %p\n",
23 | pid, execname, probefunc, arg0);
24 | stack(4);
25 | }
26 |
--------------------------------------------------------------------------------
/scripts/dtrace/deblock.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | #define VFSMNTPT(vfs) ((vfs)->vfs_vnodecovered \
4 | ? stringof((vfs)->vfs_vnodecovered->v_path) \
5 | : "???")
6 | #define NBITSMINOR 32
7 | #define MAXMIN 0xFFFFFFFF
8 |
9 | fbt::fop_write:entry
10 | /args[1]->uio_resid != 0/ {
11 | this->dev = args[0]->v_vfsp->vfs_dev;
12 | @vfs[getmajor(this->dev),
13 | getminor(this->dev),
14 | VFSMNTPT(args[0]->v_vfsp)] = sum(args[1]->uio_resid);
15 | }
16 |
17 | io:::start
18 | /args[0]->b_bcount != 0 && args[0]->b_flags & B_WRITE/ {
19 | @bio[args[1]->dev_major,
20 | args[1]->dev_minor,
21 | args[1]->dev_statname] = sum(args[0]->b_bcount);
22 | }
23 |
24 | tick-1s {
25 | normalize(@vfs, 1024); normalize(@bio, 1024);
26 |
27 | printf("%9s %16s %8s BDEV KB/s\n", "DEV_T", "NAME", "VFS KB/s");
28 | printa("%3d,%-5d %16s %8@u %@u\n", @vfs, @bio);
29 |
30 | trunc(@vfs); trunc(@bio);
31 | }
--------------------------------------------------------------------------------
/scripts/dtrace/forktime.d:
--------------------------------------------------------------------------------
1 | uint64_t tm_fork_start[int];
2 | uint64_t tm_fork_end[int];
3 | uint64_t tm_exec_start[int];
4 | uint64_t tm_exec_end[int];
5 |
6 | syscall::*fork*:entry {
7 | self->tm_fork_start = timestamp;
8 | }
9 | syscall::*fork*:return
10 | /arg1 > 0/
11 | {
12 | tm_fork_start[arg1] = self->tm_fork_start;
13 | }
14 |
15 | proc:::start {
16 | tm_fork_end[pid] = timestamp;
17 | }
18 | proc:::exec {
19 | tm_exec_start[pid] = timestamp;
20 | }
21 | proc:::exec-* {
22 | tm_exec_end[pid] = timestamp;
23 | }
24 |
25 | proc:::exit
26 | / tm_fork_start[pid] > 0 && tm_fork_end[pid] > 0 &&
27 | tm_exec_start[pid] > 0 && tm_exec_end[pid] > 0 /
28 | {
29 | @fork[curpsinfo->pr_fname, curpsinfo->pr_psargs] =
30 | avg(tm_fork_end[pid] - tm_fork_start[pid]);
31 | @postfork[curpsinfo->pr_fname, curpsinfo->pr_psargs] =
32 | avg(tm_exec_start[pid] - tm_fork_end[pid]);
33 | @exec[curpsinfo->pr_fname, curpsinfo->pr_psargs] =
34 | avg(tm_exec_end[pid] - tm_exec_start[pid]);
35 | @proc[curpsinfo->pr_fname, curpsinfo->pr_psargs] =
36 | avg(timestamp - tm_exec_end[pid]);
37 |
38 | tm_fork_start[pid] = 0; tm_fork_end[pid] = 0;
39 | tm_exec_start[pid] = 0; tm_exec_end[pid] = 0;
40 | }
41 |
42 | tick-1s {
43 | normalize(@fork, 1000); normalize(@postfork, 1000);
44 | normalize(@exec, 1000); normalize(@proc, 1000);
45 |
46 | printf("%32s %8s %8s %8s %8s\n",
47 | "COMMAND", "FORK", "POSTFORK", "EXEC", "PROC");
48 | printa("%10s %22s %@6dus %@6dus %@6dus %@6dus\n",
49 | @fork, @exec, @postfork, @proc);
50 |
51 | clear(@fork); clear(@postfork); clear(@exec); clear(@proc);
52 | }
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/scripts/dtrace/hotspot.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qs
2 |
3 | #pragma D option switchrate=10hz
4 |
5 | hotspot$target:::class-loaded
6 | {
7 | printf("%12s [???] %s\n", probename, stringof(copyin(arg0, arg1)));
8 | }
9 |
10 | hotspot$target:::method-entry,
11 | hotspot$target:::method-return
12 | {
13 | printf("%12s [%3d] %s.%s\n", probename, arg0,
14 | stringof(copyin(arg1, arg2)),
15 | stringof(copyin(arg3, arg4)));
16 | }
17 |
18 | hotspot$target:::thread-start,
19 | hotspot$target:::thread-stop
20 | {
21 | printf("%12s [%3d] %s\n", probename, arg3,
22 | stringof(copyin(arg0, arg1)));
23 | }
24 |
25 | hotspot$target:::monitor-contended-enter,
26 | hotspot$target:::monitor-contended-exit
27 | {
28 | printf("%12s [%3d] %s\n", probename, arg0,
29 | stringof(copyin(arg2, arg3)));
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/scripts/dtrace/kmemstat.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | #define CACHE_NAME(arg) ((kmem_cache_t*) arg)->cache_name
4 |
5 | fbt::kmem_cache_alloc:entry {
6 | @allocs[CACHE_NAME(arg0)] = count();
7 | }
8 |
9 | fbt::kmem_cache_free:entry {
10 | @frees[CACHE_NAME(arg0)] = count();
11 | }
12 |
13 | tick-1s {
14 | printf("%8s %8s %s\n", "ALLOCS", "FREES", "SLAB");
15 | printa("%@8u %@8u %s\n", @allocs, @frees);
16 |
17 | trunc(@allocs); trunc(@frees);
18 | }
--------------------------------------------------------------------------------
/scripts/dtrace/mtxtime.d:
--------------------------------------------------------------------------------
1 | pid$target::mutex_lock_impl:entry
2 | {
3 | self->mtxtime = timestamp;
4 | }
5 |
6 | plockstat$target:::mutex-acquire
7 | / self->mtxtime != 0 /
8 | {
9 | @[ustack()] = quantize(timestamp - self->mtxtime);
10 | self->mtxtime = 0;
11 | }
12 |
13 | pid$target::experiment_unconfigure:entry
14 | {
15 | printa(@);
16 | }
--------------------------------------------------------------------------------
/scripts/dtrace/openaggr.d:
--------------------------------------------------------------------------------
1 | syscall::openat*:entry
2 | /(arg2 & O_CREAT) == O_CREAT/ {
3 | @create[execname, pid] = count();
4 | }
5 |
6 | syscall::openat*:entry
7 | /(arg2 & O_CREAT) == 0/ {
8 | @open[execname, pid] = count();
9 | }
10 |
11 | syscall::openat*:return
12 | / arg1 > 0 / {
13 | @success[execname, pid] = count();
14 | }
15 |
16 | tick-$1s {
17 | printf("%Y\n", walltimestamp);
18 | printf("%12s %6s %6s %6s %s\n",
19 | "EXECNAME", "PID", "CREATE", "OPEN", "SUCCESS");
20 | printa("%12s %6d %@6d %@6d %@d\n", @create, @open, @success);
21 | trunc(@create); trunc(@open); trunc(@success);
22 | }
--------------------------------------------------------------------------------
/scripts/dtrace/opentrace.d:
--------------------------------------------------------------------------------
1 | /* These constants are already defined in /usr/lib/dtrace/io.d
2 | inline int O_WRONLY = 1;
3 | inline int O_RDWR = 2;
4 | inline int O_APPEND = 8;
5 | inline int O_CREAT = 256;
6 | */
7 |
8 | this string flag_str;
9 |
10 | syscall::openat*:entry {
11 | self->path = copyinstr(arg1);
12 | self->flags = arg2;
13 | }
14 |
15 | syscall::openat*:return
16 | {
17 | this->flags_str = strjoin(
18 | self->flags & O_WRONLY
19 | ? "O_WRONLY"
20 | : self->flags & O_RDWR
21 | ? "O_RDWR"
22 | : "O_RDONLY",
23 | strjoin(
24 | self->flags & O_APPEND ? "|O_APPEND" : "",
25 | self->flags & O_CREAT ? "|O_CREAT" : ""));
26 |
27 | printf("%s[%d(%d:%d)] open(\"%s\", %s) = %d\n",
28 | execname, pid, uid, gid,
29 | self->path, this->flags_str, arg1);
30 | }
--------------------------------------------------------------------------------
/scripts/dtrace/pagefault.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | /**
4 | * pagefault.d
5 | *
6 | * Traces page faults which are handled by as_fault()
7 | *
8 | * Tested on Solaris 11
9 | */
10 |
11 | string fault_type[4];
12 | string seg_rw_type[6];
13 | string prot[8];
14 |
15 | #define DUMP_AS_FAULT() \
16 | printf("as_fault pid: %d as: %p\n", pid, self->as); \
17 | printf("\taddr: %p size: %d flags: %s|%s \n", \
18 | self->addr, self->size, \
19 | fault_type[self->pf_type], \
20 | seg_rw_type[self->pf_rw] \
21 | )
22 |
23 | #define PROT(p) prot[(p) & 0x7], \
24 | ((p) & 0x8) ? "u" : "-"
25 |
26 | #define VNODE_NAME(vp) (vp) \
27 | ? ((vp)->v_path) \
28 | ? stringof((vp)->v_path) \
29 | : "???" \
30 | : "[ anon ]"
31 |
32 | #define DUMP_SEG_VN(seg, seg_vn) \
33 | printf("\t[%p:%p] %s%s\n\tvn: %s\n\tamp: %p:%d \n", \
34 | (seg)->s_base, (seg)->s_base + (seg)->s_size, \
35 | PROT((seg_vn)->prot), VNODE_NAME((seg_vn)->vp), \
36 | (seg_vn)->amp, (seg_vn)->anon_index \
37 | )
38 |
39 | #define IS_SEG_VN(s) (((struct seg*) s)->s_ops == &`segvn_ops)
40 |
41 | BEGIN {
42 | /* See vm/seg_enum.h */
43 | fault_type[0] = "F_INVAL"; fault_type[1] = "F_PROT";
44 | fault_type[2] = "F_SOFTLOCK"; fault_type[3] = "F_SOFTUNLOCK";
45 |
46 | seg_rw_type[0] = "S_OTHER"; seg_rw_type[1] = "S_READ";
47 | seg_rw_type[2] = "S_WRITE"; seg_rw_type[3] = "S_EXEC";
48 | seg_rw_type[4] = "S_CREATE"; seg_rw_type[5] = "S_READ_NOCOW";
49 |
50 | prot[0] = "---"; prot[1] = "r--";
51 | prot[2] = "-w-"; prot[3] = "rw-";
52 | prot[4] = "--x"; prot[5] = "r-x";
53 | prot[6] = "-wx"; prot[7] = "rwx";
54 | }
55 |
56 | fbt::as_fault:entry {
57 | self->in_fault = 1;
58 |
59 | self->as = args[1];
60 | self->addr = args[2];
61 | self->size = args[3];
62 |
63 | self->pf_type = args[4];
64 | self->pf_rw = args[5];
65 | }
66 |
67 | fbt::as_fault:return
68 | {
69 | self->in_fault = 0;
70 | }
71 |
72 | fbt::as_segat:return
73 | /self->in_fault && arg1 == 0/
74 | {
75 | DUMP_AS_FAULT();
76 | }
77 |
78 | fbt::as_segat:return
79 | /self->in_fault && arg1 != 0 && IS_SEG_VN(arg1)/
80 | {
81 | this->seg = (struct seg*) arg1;
82 | this->seg_vn = (segvn_data_t*) this->seg->s_data;
83 |
84 | DUMP_AS_FAULT();
85 | DUMP_SEG_VN(this->seg, this->seg_vn);
86 | }
87 |
--------------------------------------------------------------------------------
/scripts/dtrace/pfstat.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | #define VNODE_NAME(vp) \
4 | (vp) ? ((vp)->v_path) \
5 | ? stringof((vp)->v_path) : "???" : "[ anon ]"
6 |
7 | #define IS_SEG_VN(s) (((struct seg*) s)->s_ops == &`segvn_ops)
8 |
9 | fbt::as_fault:entry {
10 | self->in_fault = 1;
11 | }
12 | fbt::as_fault:return {
13 | self->in_fault = 0;
14 | }
15 |
16 | fbt::as_segat:return
17 | /self->in_fault && arg1 == 0/ {
18 | @faults["???"] = count();
19 | }
20 |
21 | fbt::as_segat:return
22 | /self->in_fault && arg1 != 0 && IS_SEG_VN(arg1)/ {
23 | this->seg = (struct seg*) arg1;
24 | this->seg_vn = (segvn_data_t*) this->seg->s_data;
25 |
26 | @faults[VNODE_NAME(this->seg_vn->vp)] = count();
27 | }
28 |
29 | tick-1s {
30 | printf("%8s %s\n", "FAULTS", "VNODE");
31 | printa("%@8u %s\n", @faults);
32 | trunc(@faults);
33 | }
--------------------------------------------------------------------------------
/scripts/dtrace/proc.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | #define PARENT_EXECNAME(thread) \
4 | (thread->t_procp->p_parent != NULL) \
5 | ? stringof(thread->t_procp->p_parent->p_user.u_comm) \
6 | : "???"
7 |
8 | proc:::, syscall::fork*:entry, syscall::exec*:entry,
9 | syscall::wait*:entry {
10 | printf("%6d[%8s]/%6d[%8s] %s::%s:%s\n",
11 | pid, execname, ppid, PARENT_EXECNAME(curthread),
12 | probeprov, probefunc, probename);
13 | }
14 |
15 | proc:::create {
16 | printf("\tPID: %d -> %d\n", curpsinfo->pr_pid, args[0]->pr_pid);
17 | }
18 |
19 |
20 | proc:::exec {
21 | printf("\tfilename: %s\n", args[0]);
22 | }
23 |
24 | proc:::exit {
25 | printf("\treturn code: %d\n", args[0]);
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/dtrace/pthread.d:
--------------------------------------------------------------------------------
1 | #!/usr/bin/dtrace
2 | #pragma D option bufsize=8m
3 | #pragma D option switchrate=100hz
4 |
5 | pid$target::pthread_create:entry {
6 | self->thread_id_ptr = (uintptr_t) arg0;
7 | self->thread_func = arg2;
8 | self->thread_arg = arg3;
9 | }
10 | pid$target::pthread_create:return {
11 | this->thread_id = * (uint_t*) copyin(self->thread_id_ptr, sizeof(uint_t));
12 | printf("[%d] pthread_create %x ", tid, this->thread_id);
13 | usym(self->thread_func);
14 | printf("(%x)\n", self->thread_arg);
15 | }
16 | pid$target::pthread_join:entry {
17 | self->thread_id = (uint_t) arg0;
18 | printf("[%d] pthread_join %x\n", tid, self->thread_id);
19 | }
20 | pid$target::pthread_join:return {
21 | printf("[%d] pthread_join:return %x -> %d\n", tid, self->thread_id, arg1);
22 | }
23 |
24 | plockstat$target:::,
25 | pid$target::pthread_cond_*wait*:entry,
26 | pid$target::pthread_cond_*wait*:return,
27 | pid$target::pthread_cond_signal:entry,
28 | pid$target::pthread_cond_broadcast:entry {
29 | printf("[%d] %s:%s ", tid, probefunc, probename);
30 | usym(arg0);
31 | printf("[%p]\n", arg0);
32 | ustack(6);
33 | }
--------------------------------------------------------------------------------
/scripts/dtrace/pycode.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -Cs
2 |
3 | #include "pycode.h"
4 |
5 | #define GET_Py3_STRING(obj) (((PyUnicodeObject*) copyin((uintptr_t) obj, \
6 | sizeof(PyUnicodeObject)))->flags[0] & 0xE0) \
7 | ? copyinstr(((uintptr_t) obj) + sizeof(PyUnicodeObject)) : "??>"
8 |
9 | foo$target::: {}
10 |
11 | pid$target::PyEval_EvalCodeEx:entry {
12 | self->co = (PyCodeObject*) copyin(arg0, sizeof(PyCodeObject));
13 |
14 | trace(GET_Py3_STRING(self->co->co_filename));
15 | trace(GET_Py3_STRING(self->co->co_name));
16 | trace(self->co->co_firstlineno);
17 | }
--------------------------------------------------------------------------------
/scripts/dtrace/pycode.h:
--------------------------------------------------------------------------------
1 | #ifndef PY_CODE_H
2 | #define PY_CODE_H
3 |
4 | /**
5 | * This is forward definitions taken from Include/object.h and Include/code.h
6 | * to support extraction of Python 3.4 interpreter state
7 | */
8 |
9 | typedef long ssize_t;
10 |
11 | typedef struct _object {
12 | /* _PyObject_HEAD_EXTRA */
13 | ssize_t ob_refcnt;
14 | struct PyObject *ob_type;
15 | } PyObject;
16 |
17 | /* Bytecode object */
18 | typedef struct _code {
19 | PyObject base;
20 | int co_argcount; /* #arguments, except *args */
21 | int co_kwonlyargcount; /* #keyword only arguments */
22 | int co_nlocals; /* #local variables */
23 | int co_stacksize; /* #entries needed for evaluation stack */
24 | int co_flags; /* CO_..., see below */
25 | PyObject *co_code; /* instruction opcodes */
26 | PyObject *co_consts; /* list (constants used) */
27 | PyObject *co_names; /* list of strings (names used) */
28 | PyObject *co_varnames; /* tuple of strings (local variable names) */
29 | PyObject *co_freevars; /* tuple of strings (free variable names) */
30 | PyObject *co_cellvars; /* tuple of strings (cell variable names) */
31 | /* The rest doesn't count for hash or comparisons */
32 | unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
33 | PyObject *co_filename; /* unicode (where it was loaded from) */
34 | PyObject *co_name; /* unicode (name, for reference) */
35 | int co_firstlineno; /* first source line number */
36 | PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
37 | Objects/lnotab_notes.txt for details. */
38 | void *co_zombieframe; /* for optimization only (see frameobject.c) */
39 | PyObject *co_weakreflist; /* to support weakrefs to code objects */
40 | } PyCodeObject;
41 |
42 | /**
43 | * Compact ASCII object from Python3 -- data starts after PyUnicodeObject -- only if compact, ascii
44 | * and ready flags are set
45 | */
46 | typedef struct _unicode {
47 | PyObject base;
48 | ssize_t length;
49 | ssize_t hash;
50 | char flags[4];
51 | void* wstr;
52 | } PyUnicodeObject;
53 |
54 | #endif
--------------------------------------------------------------------------------
/scripts/dtrace/pymalloc.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCZs
2 |
3 | BEGIN {
4 | self->depth = 0;
5 | }
6 |
7 | foo$target::: {
8 | /* This probe is just a workaround for -xlazyload */
9 | }
10 |
11 | python$target:::function-entry {
12 | func_stack[self->depth] = arg1;
13 | file_stack[self->depth] = arg0;
14 |
15 | self->depth++;
16 | }
17 | python$target:::function-return {
18 | self->depth--;
19 | }
20 |
21 | pid$target::malloc:entry
22 | / func_stack[self->depth] != 0 / {
23 | @mallocs[copyinstr(func_stack[self->depth]),
24 | copyinstr(file_stack[self->depth])] = sum(arg0);
25 | }
--------------------------------------------------------------------------------
/scripts/dtrace/readahead.d:
--------------------------------------------------------------------------------
1 | #!/usr/sbin/dtrace -qCs
2 |
3 | #define VFSMNTPT(vfs) ((vfs)->vfs_vnodecovered \
4 | ? stringof((vfs)->vfs_vnodecovered->v_path) \
5 | : "???")
6 | #define HASDI(bp) (((struct buf*) bp)->b_dip != 0)
7 | #define DEVINFO(bp) xlate((struct buf*) bp)
8 |
9 | fbt::fop_read:entry
10 | /args[1]->uio_resid != 0/ {
11 | this->dev = args[0]->v_vfsp->vfs_dev;
12 | @vfs[getmajor(this->dev),
13 | getminor(this->dev),
14 | VFSMNTPT(args[0]->v_vfsp)] = count();
15 | }
16 |
17 | io:::start
18 | /args[0]->b_bcount != 0 && args[0]->b_flags & B_READ/ {
19 | @bio[args[1]->dev_major,
20 | args[1]->dev_minor,
21 | args[1]->dev_statname] = count();
22 | }
23 |
24 | scsi-transport-dispatch
25 | /arg0 != 0 && HASDI(arg0)/ {
26 | @scsi[DEVINFO(arg0)->dev_major,
27 | DEVINFO(arg0)->dev_minor,
28 | DEVINFO(arg0)->dev_statname] = count();
29 | }
30 |
31 | tick-1s {
32 | printf("%9s %16s %8s %8s SCSI OP/s\n", "DEV_T", "NAME", "VFS OP/s", "BDEV OP/s");
33 | printa("%3d,%-5d %16s %8@u %@8u %@u\n", @vfs, @bio, @scsi);
34 |
35 | trunc(@vfs); trunc(@bio); trunc(@scsi);
36 | }
37 |
--------------------------------------------------------------------------------
/scripts/dtrace/stat.d:
--------------------------------------------------------------------------------
1 | struct stat_info {
2 | long long st_size;
3 | };
4 |
5 | translator struct stat_info < uintptr_t s > {
6 | st_size = * ((long long*) copyin(s + offsetof(struct stat64_32, st_size),
7 | sizeof (long long)));
8 | };
9 |
10 | syscall::fstatat64:entry
11 | {
12 | self->filename = copyinstr(arg1);
13 | self->statptr = arg2;
14 | }
15 |
16 | syscall::fstatat64:return
17 | {
18 | printf("STAT %s size: %d\n", self->filename,
19 | xlate < struct stat_info* > (self->statptr)->st_size);
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/scripts/dtrace/topphp.d:
--------------------------------------------------------------------------------
1 | ap*:::process-request-entry {
2 | self->uri = copyinstr(arg1);
3 | }
4 |
5 | php*:::function-entry {
6 | self->starttime = timestamp;
7 | }
8 |
9 | php*:::function-return
10 | / self->starttime != 0 / {
11 | this->func = strjoin(copyinstr(arg3),
12 | strjoin(copyinstr(arg4), copyinstr(arg0)));
13 | @[this->func, self->uri] = avg(timestamp - self->starttime);
14 | }
15 |
16 | END {
17 | printa(@);
18 | }
--------------------------------------------------------------------------------
/scripts/dtrace/web.d:
--------------------------------------------------------------------------------
1 | #pragma D option strsize=2048
2 | #pragma D option bufsize=128M
3 | #pragma D option switchrate=20hz
4 |
5 | ap*:::internal-redirect {
6 | printf("[httpd] redirect\t'%s' -> '%s'\n", copyinstr(arg0), copyinstr(arg1));
7 | }
8 |
9 | ap*:::read-request-entry {
10 | printf("[httpd] read-request\n");
11 | }
12 |
13 | ap*:::read-request-success {
14 | this->servername = (arg3) ? copyinstr(arg3) : "???";
15 |
16 | printf("[httpd] read-request\t%s %s %s [status: %d]\n",
17 | copyinstr(arg1), this->servername, copyinstr(arg2), arg4);
18 | }
19 |
20 | ap*:::process-request-entry {
21 | printf("[httpd] process-request\t'%s'\n", copyinstr(arg1));
22 | }
23 |
24 | ap*:::process-request-return {
25 | printf("[httpd] process-request\t'%s' access-status: %d\n",
26 | copyinstr(arg1), arg2);
27 | }
28 |
29 | php*:::request-startup,
30 | php*:::request-shutdown {
31 | printf("[ PHP ] %s\t%s '%s' file: %s \n", probename,
32 | copyinstr(arg2), copyinstr(arg1), copyinstr(arg0));
33 | }
34 |
35 | php*:::function-entry,
36 | php*:::function-return {
37 | printf("[ PHP ] %s\t%s%s%s file: %s:%d \n", probename,
38 | copyinstr(arg3), copyinstr(arg4), copyinstr(arg0),
39 | basename(copyinstr(arg1)), arg2);
40 | }
41 |
42 | mysql*:::query-parse-start {
43 | self->parsequery = copyinstr(arg0, 1024);
44 | }
45 |
46 | mysql*:::query-parse-done {
47 | printf("[MySQL] query-parse\t'%s' status: %d\n", self->parsequery, arg0);
48 | }
49 |
50 | mysql*:::query-exec-start {
51 | self->execquery = copyinstr(arg0, 1024);
52 | }
53 |
54 | mysql*:::query-exec-done {
55 | printf("[MySQL] query-exec\t'%s' status: %d\n", self->execquery, arg0);
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/scripts/dtrace/wstat.d:
--------------------------------------------------------------------------------
1 | #pragma D option aggsortkey
2 | #pragma D option aggsortkeypos=0
3 |
4 | syscall::write:entry
5 | {
6 | @wbytes[pid, execname, arg0] = sum(arg2);
7 | @wops[pid, execname, arg0] = count();
8 | }
9 |
10 | tick-1s
11 | {
12 | normalize(@wbytes, 1024);
13 |
14 | printf("%5s %12s %3s %7s %7s\n",
15 | "PID", "EXECNAME", "FD", "OPS", "KBYTES");
16 | printa("%5u %12s %3u %7@d %7@dK\n", @wops, @wbytes);
17 | clear(@wbytes);
18 | }
--------------------------------------------------------------------------------
/scripts/src/hellouser.py:
--------------------------------------------------------------------------------
1 | import os
2 | print "Hello, " + os.getenv('LOGNAME', 'anonymous') + '!'
3 |
4 |
--------------------------------------------------------------------------------
/scripts/src/java/Greeter.java:
--------------------------------------------------------------------------------
1 | public class Greeter {
2 | public static void main(String[] args) {
3 | Greeting greeting = new Greeting();
4 | GreetingThread threads[] = new GreetingThread[4];
5 |
6 | for(int i = 0; i < 4; ++i) {
7 | threads[i] = new GreetingThread(greeting);
8 | threads[i].start();
9 | }
10 |
11 | for(int i = 0; i < 4; ++i) {
12 | try {
13 | threads[i].join();
14 | }
15 | catch(InterruptedException ie) {
16 | }
17 | }
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/scripts/src/java/Greeting.java:
--------------------------------------------------------------------------------
1 | public class Greeting {
2 | public synchronized void greet() {
3 | System.out.println("Hello, DTrace!");
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/scripts/src/java/GreetingThread.java:
--------------------------------------------------------------------------------
1 | class GreetingThread extends Thread {
2 | Greeting greeting;
3 |
4 | GreetingThread(Greeting greeting) {
5 | this.greeting = greeting;
6 | super.setDaemon(true);
7 | }
8 |
9 | public void run() {
10 | while(true) {
11 | greeting.greet();
12 | try {
13 | Thread.sleep(1000);
14 | } catch (InterruptedException e) {
15 | }
16 | }
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/scripts/src/jsdt/Greeting.java:
--------------------------------------------------------------------------------
1 | public class Greeting {
2 | GreetingProvider provider;
3 |
4 | public Greeting(GreetingProvider provider) {
5 | this.provider = provider;
6 | }
7 |
8 | public void greet(int greetingId) {
9 | provider.greetingStart(greetingId);
10 | System.out.println("Hello DTrace!");
11 | provider.greetingEnd(greetingId);
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/scripts/src/jsdt/GreetingProvider.java:
--------------------------------------------------------------------------------
1 | import com.sun.tracing.Provider;
2 |
3 | public interface GreetingProvider extends Provider {
4 | public void greetingStart(int greetingId);
5 | public void greetingEnd(int greetingId);
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/scripts/src/jsdt/JSDT.java:
--------------------------------------------------------------------------------
1 | import com.sun.tracing.*;
2 |
3 | public class JSDT {
4 | static public void main(String[] args) {
5 | ProviderFactory providerFactory =
6 | new sun.tracing.dtrace.DTraceProviderFactory();
7 | GreetingProvider greetingProvider = (GreetingProvider)
8 | providerFactory.createProvider(GreetingProvider.class);
9 |
10 | Greeting greeter = new Greeting(greetingProvider);
11 |
12 | for(int id = 0; id < 100; ++id) {
13 | greeter.greet(id);
14 |
15 | try { Thread.sleep(500); }
16 | catch(InterruptedException ie) {}
17 | }
18 |
19 | greetingProvider.dispose();
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/scripts/src/lab3.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | int main(int argc, char* argv[]) {
6 | while(--argc > 0) {
7 | memset(argv[argc], 'X', strlen(argv[argc]));
8 | }
9 |
10 | open("/etc/passwd", O_RDONLY);
11 | return 0;
12 | }
--------------------------------------------------------------------------------
/scripts/src/openproc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import re
4 | import sys
5 |
6 | # ----------------------------
7 | # openproc.py - Collect data from opentrace.py and merge :entry and :return probes
8 |
9 | # Open trace file or use stdin
10 | try:
11 | inf = file(sys.argv[1], 'r')
12 | except OSError as ose:
13 | print ose
14 | print '''openproc.py [filename]'''
15 | sys.exit(1)
16 | except IndexError:
17 | inf = sys.stdin
18 |
19 | # Convert time to human time
20 | def human_time(ns):
21 | ns = float(ns)
22 | for unit in ['ns', 'us', 'ms']:
23 | if abs(ns) < 1000.0:
24 | break
25 | ns /= 1000.0
26 | else:
27 | unit = 's'
28 | return "%.2f %s" % (ns, unit)
29 |
30 | # Parse /etc/passwd and create UID-to-USERNAME map
31 | uid_name = lambda user: (int(user[2]), user[0])
32 | users = dict([uid_name(user.split(':'))
33 | for user in file('/etc/passwd')])
34 |
35 | # Per-PID state - tuples (start time, file name)
36 | state = {}
37 |
38 | # Regular expressions for parsing tracer output
39 | re_entry = re.compile("=> uid: (\d+) pid: (\d+) open: (.*?) (\d+)")
40 | re_return = re.compile("<= uid: (\d+) pid: (\d+) ret: (-?\d+) (\d+)")
41 |
42 | for line in inf:
43 | if line.startswith('=>'):
44 | # :entry probe, extract start time and filename
45 | m = re_entry.match(line)
46 | _, pid, fname, tm = m.groups()
47 |
48 | state[int(pid)] = (int(tm), fname)
49 | elif line.startswith('<='):
50 | # :return probe, get return value, timestamp and print information
51 | m = re_return.match(line)
52 | uid, pid, ret, tm = map(int, m.groups())
53 |
54 | if pid not in state:
55 | continue
56 |
57 | status = 'FD %d' % ret if ret >= 0 else 'ERROR %d' % ret
58 |
59 | print 'OPEN %s %d %s => %s [%s]' % (users.get(uid, str(uid)),
60 | pid, state[pid][1], status,
61 | human_time(tm - state[pid][0]))
62 | del state[pid]
63 |
--------------------------------------------------------------------------------
/scripts/stap/callgraph.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | global traceme;
4 |
5 | probe syscall.open {
6 | if(pid() != target() || filename != "not_exists")
7 | next;
8 |
9 | traceme = target();
10 |
11 | printf("=> syscall.open [%s]\n", execname());
12 | }
13 |
14 | probe syscall.open.return {
15 | if(pid() == target()) {
16 | traceme = 0;
17 | }
18 | }
19 |
20 | probe kernel.function("*@fs/*").call ?,
21 | kernel.function("*@fs/*").return ? {
22 | if(!traceme || traceme != pid())
23 | next;
24 |
25 | if(!is_return()) {
26 | printf("%s -> %s\n", indent( 1), probefunc());
27 | }
28 | else {
29 | ret = 0;
30 | if(@defined($return))
31 | ret = $return;
32 |
33 | printf("%s <- %s [%d]\n", indent(-1), probefunc(), ret);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/scripts/stap/deblock.stp:
--------------------------------------------------------------------------------
1 | global vfstp, biotp;
2 |
3 | probe kernel.function("vfs_write") {
4 | file = $file;
5 | if(!file) next;
6 |
7 | sb = @cast(file, "file")->f_path->mnt->mnt_sb;
8 | if(!sb) next;
9 |
10 | bdev = @cast(sb, "super_block")->s_bdev;
11 | if(bdev)
12 | vfstp[bdev] <<< $count;
13 | }
14 |
15 | probe ioblock.request {
16 | if(bio_rw_num(rw) != BIO_WRITE)
17 | next;
18 |
19 | biotp[bdev] <<< size;
20 | }
21 |
22 | probe timer.s(1) {
23 | printf("%12s %8s BDEV KB/s\n", "BDEV", "VFS KB/s");
24 | foreach([bdev] in vfstp) {
25 | printf("%12s %8d %d\n", bdevname(bdev),
26 | @sum(vfstp[bdev]) / 1024,
27 | @sum(biotp[bdev]) / 1024);
28 | }
29 | delete vfstp; delete biotp;
30 | }
--------------------------------------------------------------------------------
/scripts/stap/forktime.stp:
--------------------------------------------------------------------------------
1 | global tm_fork_start_par[128], tm_fork_start[128], tm_fork_end[128],
2 | tm_exec_start[128], tm_exec_end[128], p_argstr[128];
3 | global fork[128], postfork[128], exec[128], proc[128];
4 |
5 | probe syscall.fork {
6 | tm_fork_start_par[tid()] = local_clock_us();
7 | }
8 | probe syscall.fork.return {
9 | if($return > 1) {
10 | tm_fork_start[$return] = tm_fork_start_par[tid()];
11 | delete tm_fork_start_par[tid()];
12 | }
13 | }
14 | probe kprocess.start {
15 | tm_fork_end[pid()] = local_clock_us();
16 | }
17 | probe kprocess.exec {
18 | p_argstr[pid()] = argstr;
19 | tm_exec_start[pid()] = local_clock_us();
20 | }
21 | probe kprocess.exec_complete {
22 | tm_exec_end[pid()] = local_clock_us();
23 | }
24 | probe kprocess.exit {
25 | argstr = p_argstr[pid()];
26 |
27 | fork[execname(), argstr] <<< tm_fork_end[pid()] - tm_fork_start[pid()];
28 | postfork[execname(), argstr] <<< tm_exec_start[pid()] - tm_fork_end[pid()];
29 | exec[execname(), argstr] <<< tm_exec_end[pid()] - tm_exec_start[pid()];
30 | proc[execname(), argstr] <<< local_clock_us() - tm_exec_end[pid()];
31 |
32 | delete tm_fork_start[pid()]; delete tm_fork_end[pid()];
33 | delete tm_exec_start[pid()]; delete tm_exec_end[pid()];
34 | delete p_argstr[pid()];
35 | }
36 |
37 | probe timer.s(1) {
38 | printf("%48s %8s %8s %8s %8s\n",
39 | "COMMAND", "FORK", "POSTFORK", "EXEC", "PROC");
40 | foreach([execname, args] in proc) {
41 | printf("%10s %36s %6dus %6dus %6dus %6dus\n", execname, args,
42 | @avg(fork[execname, args]),
43 | @avg(postfork[execname, args]),
44 | @avg(exec[execname, args]),
45 | @avg(proc[execname, args]));
46 | }
47 | delete fork; delete postfork; delete exec; delete proc;
48 | }
--------------------------------------------------------------------------------
/scripts/stap/hotspot.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | probe hotspot.class_loaded
4 | {
5 | printf("%12s [???] %s\n", name, class);
6 | }
7 |
8 | probe hotspot.method_entry, hotspot.method_return
9 | {
10 | printf("%12s [%3d] %s.%s\n", name, thread_id, class, method);
11 | }
12 |
13 | probe hotspot.thread_start, hotspot.thread_stop
14 | {
15 | printf("%12s [%3d] %s\n", name, id, thread_name);
16 | }
17 |
18 | probe hotspot.monitor_contended_enter, hotspot.monitor_contended_exit
19 | {
20 | printf("%12s [%3d] %s\n", name, thread_id, class);
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/scripts/stap/kmemstat.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | global allocs, frees;
4 |
5 | probe kernel.function("kmem_cache_alloc"),
6 | kernel.function("kmem_cache_alloc_node") {
7 | cache = @choose_defined($s, $cachep);
8 | name = kernel_string(@cast(cache, "struct kmem_cache")->name);
9 |
10 | allocs[name] <<< 1;
11 | }
12 |
13 | probe kernel.function("kmem_cache_free") {
14 | cache = @choose_defined($s, $cachep);
15 | name = kernel_string(@cast(cache, "struct kmem_cache")->name);
16 |
17 | frees[name] <<< 1;
18 | }
19 |
20 | probe timer.s(1) {
21 | printf("%8s %8s %s\n", "ALLOCS", "FREES", "SLAB");
22 | foreach([cache] in allocs) {
23 | printf("%8u %8u %s\n", @count(allocs[cache]),
24 | @count(frees[cache]), cache);
25 | }
26 |
27 | delete allocs;
28 | delete frees;
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/stap/lstat.stp:
--------------------------------------------------------------------------------
1 | probe lstat {
2 | printf("%s %d\n", filename, size);
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/scripts/stap/mtxtime.stp:
--------------------------------------------------------------------------------
1 | global mtxtime[128], mtxlockt;
2 |
3 | @define libpthread %( "/lib64/libpthread.so.0" %)
4 | @define tsexperiment %( "/opt/tsload/bin/tsexperiment" %)
5 |
6 | probe process(@libpthread).mark("mutex_entry") {
7 | if(pid() != target()) next;
8 |
9 | mtxtime[tid()] = local_clock_ns();
10 | }
11 |
12 | probe process(@libpthread).mark("mutex_acquired") {
13 | if(pid() != target()) next;
14 |
15 | tm = mtxtime[tid()];
16 | if(tm == 0) next;
17 |
18 | mtxlockt[ucallers(6)] <<< local_clock_ns() - tm;
19 | delete mtxtime[tid()];
20 | }
21 |
22 | probe process(@tsexperiment).function("experiment_unconfigure") {
23 | foreach([ub] in mtxlockt) {
24 | if(@count(mtxlockt[ub]) < 100)
25 | continue;
26 |
27 | println("-=-=-=-=-=-=-=-=-=-=-=-=-");
28 | print_usyms(ub);
29 | print(@hist_log(mtxlockt[ub]));
30 | }
31 | }
--------------------------------------------------------------------------------
/scripts/stap/openaggr.stp:
--------------------------------------------------------------------------------
1 | global open, creat, success
2 | global O_CREAT = 64;
3 |
4 | probe syscall.open {
5 | if(flags & O_CREAT)
6 | creat[execname(), pid()] <<< 1;
7 | else
8 | open[execname(), pid()] <<< 1;
9 | }
10 |
11 | probe syscall.open.return {
12 | if($return >= 0)
13 | success[execname(), pid()] <<< 1;
14 | }
15 |
16 | probe timer.s($1) {
17 | println(ctime(gettimeofday_s()));
18 |
19 | printf("%12s %6s %6s %6s %s\n",
20 | "EXECNAME", "PID", "CREATE", "OPEN", "SUCCESS");
21 | foreach([en, pid+] in open) {
22 | printf("%12s %6d %6d %6d %d\n",
23 | en, pid, @count(creat[en, pid]), @count(open[en, pid]),
24 | @count(success[en, pid]));
25 | }
26 |
27 | delete open; delete creat; delete success;
28 | }
--------------------------------------------------------------------------------
/scripts/stap/opentrace.stp:
--------------------------------------------------------------------------------
1 | global O_WRONLY = 1;
2 | global O_RDWR = 2;
3 | global O_APPEND = 1024;
4 | global O_CREAT = 64;
5 |
6 | global t_path, t_flags;
7 |
8 | probe syscall.open {
9 | t_path[tid()] = filename;
10 | t_flags[tid()] = flags;
11 | }
12 |
13 | probe syscall.open.return {
14 | flags = t_flags[tid()];
15 |
16 | if(flags & O_RDWR) {
17 | flags_str = "O_RDWR";
18 | }
19 | else if(flags & O_WRONLY) {
20 | flags_str = "O_WRONLY";
21 | }
22 | else {
23 | flags_str = "O_RDONLY";
24 | }
25 | if(flags & O_APPEND) {
26 | flags_str = sprintf("%s|%s", flags_str, "O_APPEND");
27 | }
28 | if(flags & O_CREAT) {
29 | flags_str = sprintf("%s|%s", flags_str, "O_CREAT");
30 | }
31 |
32 | printf("%s[%d(%d:%d)] open(%s, %s) = %d\n",
33 | execname(), pid(), uid(), gid(),
34 | t_path[tid()], flags_str, $return);
35 | }
--------------------------------------------------------------------------------
/scripts/stap/pagefault.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | /**
4 | * pagefault.stp
5 | *
6 | * Traces page faults handled by handle_mm_fault()
7 | *
8 | * Tested on Linux 3.10 (CentOS 7)
9 | */
10 |
11 | global fault_flags;
12 | global vma_flags;
13 |
14 | probe begin {
15 | /* See include/linux/mm.h */
16 | fault_flags[0] = "WRITE"; fault_flags[1] = "NONLINEAR";
17 | fault_flags[2] = "MKWRITE"; fault_flags[3] = "ALLOW_RETRY";
18 | fault_flags[4] = "RETRY_NOWAIT"; fault_flags[5] = "KILLABLE";
19 |
20 | vma_flags[0] = "VM_GROWSDOWN"; vma_flags[2] = "VM_PFNMAP";
21 | vma_flags[3] = "VM_DENYWRITE"; vma_flags[5] = "VM_LOCKED";
22 | vma_flags[6] = "VM_IO"; vma_flags[7] = "VM_SEQ_READ";
23 | vma_flags[8] = "VM_RAND_READ"; vma_flags[9] = "VM_DONTCOPY";
24 | vma_flags[10] = "VM_DONTEXPAND"; vma_flags[12] = "VM_ACCOUNT";
25 | vma_flags[13] = "VM_NORESERVE"; vma_flags[14] = "VM_HUGETLB";
26 | vma_flags[15] = "VM_NONLINEAR"; vma_flags[16] = "VM_ARCH_1";
27 | vma_flags[18] = "VM_DONTDUMP"; vma_flags[20] = "VM_MIXEDMAP";
28 | vma_flags[21] = "VM_HUGEPAGE"; vma_flags[22] = "VM_NOHUGEPAGE";
29 | }
30 |
31 | function prot_str:string(prot: long) {
32 | return sprintf("%s%s%s%s",
33 | (prot & 0x1) ? "r" : "-",
34 | (prot & 0x2) ? "w" : "-",
35 | (prot & 0x4) ? "x" : "-",
36 | (prot & 0x8) ? "s" : "-");
37 | }
38 |
39 | function vma_flags_str:string(flags: long) {
40 | prot = flags & 0xf;
41 | mprot = (flags >> 4) & 0xf;
42 | flags = flags >> 8;
43 |
44 | for(i = 0; i < 23; ++i) {
45 | if(flags & 1) {
46 | str = sprintf("%s|%s", str, vma_flags[i]);
47 | }
48 |
49 | flags >>= 1;
50 | }
51 |
52 | return sprintf("prot: %s may: %s flags: %s",
53 | prot_str(prot), prot_str(mprot),
54 | substr(str, 1, strlen(str) - 1));
55 | }
56 |
57 | function fault_flags_str:string(flags: long) {
58 | for(i = 0; i < 6; ++i) {
59 | if(flags & 1) {
60 | str = sprintf("%s|%s", str, fault_flags[i]);
61 | }
62 |
63 | flags >>= 1;
64 | }
65 |
66 | /* Cut first pipe sign ('|') */
67 | return substr(str, 1, strlen(str) - 1);
68 | }
69 |
70 | function vm_fault_str(fault_type: long) {
71 | if(vm_fault_contains(fault_type, VM_FAULT_OOM))
72 | return "OOM";
73 | else if(vm_fault_contains(fault_type, VM_FAULT_SIGBUS))
74 | return "SIGBUS";
75 | else if(vm_fault_contains(fault_type, VM_FAULT_MINOR))
76 | return "MINOR";
77 | else if(vm_fault_contains(fault_type, VM_FAULT_MAJOR))
78 | return "MAJOR";
79 | else if(vm_fault_contains(fault_type, VM_FAULT_NOPAGE))
80 | return "NOPAGE";
81 | else if(vm_fault_contains(fault_type, VM_FAULT_LOCKED))
82 | return "LOCKED";
83 | else if(vm_fault_contains(fault_type, VM_FAULT_ERROR))
84 | return "ERROR";
85 |
86 | return "???";
87 | }
88 |
89 | probe vm.pagefault {
90 | printf("vm.pagefault pid: %d mm: %p\n", pid(), $mm);
91 | printf("\taddr: %p flags: %s\n", $address, fault_flags_str($flags));
92 | printf("\tVMA [%p:%p]\n", $vma->vm_start, $vma->vm_end);
93 | printf("\t%s\n", vma_flags_str($vma->vm_flags));
94 | printf("\tamp: %p\n", $vma->anon_vma)
95 |
96 | if($vma->vm_file != 0)
97 | printf("\tfile: %s\n", d_name($vma->vm_file->f_path->dentry))
98 | }
99 |
100 | probe vm.pagefault.return {
101 | printf("\t => pid: %d pf: %s\n", pid(), vm_fault_str(fault_type));
102 | }
103 |
--------------------------------------------------------------------------------
/scripts/stap/pfstat.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | global pfs;
4 |
5 | probe vm.pagefault {
6 | vm_file = "???";
7 | if($vma->vm_file != 0)
8 | vm_file = d_name($vma->vm_file->f_path->dentry);
9 |
10 | pfs[vm_file] <<< 1;
11 | }
12 |
13 | probe timer.s(1) {
14 | printf("%8s %s\n", "FAULTS", "VMFILE");
15 | foreach([vm_file] in pfs) {
16 | printf("%8u %s\n", @count(pfs[vm_file]), vm_file);
17 | }
18 |
19 | delete pfs;
20 | }
21 |
--------------------------------------------------------------------------------
/scripts/stap/proc.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | probe scheduler.process*, scheduler.wakeup_new, syscall.fork,
4 | syscall.exec*, syscall.exit, syscall.wait*, kprocess.* {
5 | printf("%6d[%8s]/%6d[%8s] %s\n",
6 | pid(), execname(), ppid(), pid2execname(ppid()), pn());
7 | }
8 |
9 | probe scheduler.process_fork {
10 | printf("\tPID: %d -> %d\n", parent_pid, child_pid);
11 | }
12 |
13 | probe kprocess.exec {
14 | printf("\tfilename: %s\n", filename);
15 | }
16 |
17 | probe kprocess.exit {
18 | printf("\treturn code: %d\n", code);
19 | }
20 |
--------------------------------------------------------------------------------
/scripts/stap/pthread.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env stap
2 |
3 | @define libpthread %( "/lib64/libpthread.so.0" %)
4 | @define libc %( "/lib64/libc.so.6" %)
5 |
6 | probe process(@libpthread).mark("pthread_create") {
7 | if(pid() != target()) next;
8 |
9 | thread_id = user_long($arg1);
10 | thread_caller = usymname($arg3);
11 | thread_arg = $arg4;
12 |
13 | printf("[%d] pthread_create %x %s(%x)\n", tid(),
14 | thread_id, thread_caller, thread_arg);
15 | }
16 |
17 | probe process(@libpthread).mark("pthread_start") {
18 | if(pid() != target()) next;
19 |
20 | thread_id = $arg1;
21 | printf("[%d] pthread_start %x\n", tid(), thread_id);
22 | }
23 |
24 | probe process(@libpthread).mark("pthread_join") {
25 | if(pid() != target()) next;
26 |
27 | thread_id = $arg1;
28 | printf("[%d] pthread_join %x\n", tid(), thread_id);
29 | }
30 |
31 | probe process(@libpthread).mark("pthread_join_ret") {
32 | if(pid() != target()) next;
33 |
34 | thread_id = $arg1;
35 | printf("[%d] pthread_join %x return -> %d/%d \n", tid(),
36 | thread_id, $arg2, $arg3);
37 | }
38 |
39 | probe process(@libpthread).mark("mutex_*"),
40 | process(@libpthread).mark("cond_*"),
41 | process(@libpthread).mark("rdlock_*"),
42 | process(@libpthread).mark("wrlock_*"),
43 | process(@libpthread).mark("rwlock_*") {
44 | if(pid() != target()) next;
45 |
46 | printf("[%d] %s %p\n", tid(), pn(), $arg1);
47 | print_ustack(ucallers(5));
48 | }
49 |
50 | probe process(@libpthread).mark("lll_*"),
51 | process(@libc).mark("lll_*") {
52 | if(pid() != target()) next;
53 |
54 | printf("[%d] %s\n", tid(), pn());
55 | print_ustack(ucallers(5));
56 | }
57 |
--------------------------------------------------------------------------------
/scripts/stap/pycode.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env stap
2 |
3 | @define PYTHON3_LIBRARY %( "/usr/lib64/libpython3.4m.so.1.0" %)
4 |
5 | function get_py3_string:string(uo: long) {
6 | flags = user_uint32(&@cast(uo, "PyASCIIObject", @PYTHON3_LIBRARY)->state);
7 | if(flags & 0xE0) {
8 | size = &@cast(0, "PyASCIIObject", @PYTHON3_LIBRARY)[1]
9 | return user_string(uo + size);
10 | }
11 |
12 | return "???";
13 | }
14 |
15 | probe process(@PYTHON3_LIBRARY).function("PyEval_EvalCodeEx") {
16 | code = $_co;
17 | if(code) {
18 | printf("%s %s:%d\n",
19 | get_py3_string(@cast(code, "PyCodeObject", @PYTHON3_LIBRARY)->co_name),
20 | get_py3_string(@cast(code, "PyCodeObject", @PYTHON3_LIBRARY)->co_filename),
21 | @cast(code, "PyCodeObject", @PYTHON3_LIBRARY)->co_firstlineno);
22 | }
23 | }
--------------------------------------------------------------------------------
/scripts/stap/pymalloc.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env stap
2 |
3 | @define libc %( "/lib64/libc.so.6" %)
4 |
5 | global file_stack, func_stack, mallocs, thread_depth
6 |
7 | probe python.function.entry {
8 | thread_depth[tid()]++;
9 |
10 | depth = thread_depth[tid()];
11 | file_stack[tid(), depth] = filename;
12 | func_stack[tid(), depth] = funcname;
13 | }
14 |
15 | probe python.function.return {
16 | thread_depth[tid()]--;
17 | }
18 |
19 | probe process(@libc).function("_int_malloc") {
20 | depth = thread_depth[tid()];
21 | mallocs[file_stack[tid(), depth],
22 | func_stack[tid(), depth]] <<< $bytes;
23 | }
--------------------------------------------------------------------------------
/scripts/stap/readahead.stp:
--------------------------------------------------------------------------------
1 | global vfsops, bioops, scsiops;
2 |
3 | probe kernel.function("vfs_read") {
4 | file = $file;
5 | if(!file) next;
6 |
7 | sb = @cast(file, "file")->f_path->mnt->mnt_sb;
8 | if(!sb) next;
9 |
10 | bdev = @cast(sb, "super_block")->s_bdev;
11 | if(bdev)
12 | vfsops[bdev] <<< 1;
13 | }
14 |
15 | probe ioblock.request {
16 | if(bio_rw_num(rw) != BIO_READ)
17 | next;
18 |
19 | bioops[bdev] <<< 1;
20 | }
21 |
22 | probe scsi.ioentry {
23 | bio = @cast(req_addr, "struct request")->bio;
24 | if(!bio) next;
25 |
26 | bdev = @cast(bio, "bio")->bi_bdev;
27 | if(bdev)
28 | scsiops[bdev] <<< 1;
29 | }
30 |
31 | probe timer.s(1) {
32 | printf("%12s %8s %8s SCSI OP/s\n", "BDEV", "VFS OP/s", "BDEV OP/s");
33 | foreach([bdev] in vfsops) {
34 | printf("%12s %8d %8d %d\n", bdevname(bdev), @count(vfsops[bdev]),
35 | @count(bioops[bdev]), @count(scsiops[bdev]));
36 | }
37 | delete vfsops; delete bioops; delete scsiops;
38 | }
--------------------------------------------------------------------------------
/scripts/stap/scsitrace.stp:
--------------------------------------------------------------------------------
1 | #!/usr/bin/stap
2 |
3 | global rqs, bio2rq, specs, times;
4 |
5 | function probe_print:string(bio:long) {
6 | return sprintf("%-24s %p cpu%d %u\n", pn(), bio, cpu(),
7 | gettimeofday_ns() - times[bio2rq[bio]]);
8 | }
9 |
10 | function rq_probe_print(rq:long, bio:long) {
11 | if(bio == 0)
12 | bio = @cast(rq, "struct request")->bio;
13 | return sprintf("%-24s %p %p cpu%d %u\n", pn(), bio, rq, cpu(),
14 | gettimeofday_ns() - times[bio]);
15 | }
16 |
17 | function proc_print:string() {
18 | return sprintf("\tPROC: %d/%d %s\n", pid(), tid(), execname());
19 | }
20 |
21 | function handle_bio2rq(bio:long, rq:long) {
22 | if(specs[rq] == 0) {
23 | specs[rq] = speculation();
24 | }
25 |
26 | rqs[rq] += 1;
27 | bio2rq[bio] = rq;
28 |
29 | speculate(specs[rq],
30 | rq_probe_print(rq, bio)
31 | .proc_print()
32 | .sprintf("\tBUF flags: %s %x count: %d blkno: %d comp: %s\n",
33 | bio_rw_str(@cast(bio, "bio")->bi_rw), @cast(bio, "bio")->bi_flags,
34 | @cast(bio, "bio")->bi_size, @cast(bio, "bio")->bi_sector,
35 | symname(@cast(bio, "bio")->bi_end_io))
36 | .sprintf("\tDEV %d,%d\tINO %d\n", MAJOR(@cast(bio, "bio")->bi_bdev->bd_dev),
37 | MINOR(@cast(bio, "bio")->bi_bdev->bd_dev), __bio_ino(bio)));
38 | }
39 |
40 | probe ioblock.request {
41 | times[$bio] = gettimeofday_ns();
42 | }
43 |
44 | probe kernel.function("bio_attempt_front_merge").return,
45 | kernel.function("bio_attempt_back_merge").return {
46 | if($return) {
47 | /* BIO was merged with request */
48 | rq = $req;
49 | bio = $bio;
50 |
51 | if(bio == 0) next;
52 |
53 | handle_bio2rq(bio, rq);
54 | }
55 | }
56 |
57 | probe kernel.function("get_request").return {
58 | rq = $return;
59 | bio = $bio;
60 |
61 | if(bio == 0) next;
62 |
63 | /* BIO were created a new request */
64 | handle_bio2rq(bio, rq);
65 | }
66 |
67 | probe ioscheduler.elv_add_request, ioscheduler.elv_completed_request {
68 | if(rq == 0 || specs[rq] == 0) next;
69 | speculate(specs[rq],
70 | rq_probe_print(rq, 0)
71 | .sprintf("\tDEV %d,%d\n", disk_major, disk_minor));
72 | }
73 |
74 | probe scsi.ioentry, scsi.iodone, scsi.iocompleted, scsi.iodispatching {
75 | if(req_addr == 0 || specs[req_addr] == 0) next;
76 | speculate(specs[req_addr],
77 | rq_probe_print(req_addr, 0));
78 | }
79 |
80 | probe scsi.iodispatching {
81 | if(req_addr == 0 || specs[req_addr] == 0) next;
82 | speculate(specs[req_addr],
83 | rq_probe_print(req_addr, 0)
84 | .sprintf("\tSCSI DEV %d:%d:%d:%d %s\n",
85 | host_no, channel, lun, dev_id, device_state_str)
86 | .sprintf("\tSCSI PKT flags: %x comp: %s\n",
87 | @cast(req_addr, "struct request")->cmd_flags,
88 | symname($cmd->scsi_done)));
89 | }
90 |
91 | probe ioblock.end {
92 | bio = $bio;
93 | rq = bio2rq[bio];
94 |
95 | delete bio2rq[bio];
96 | delete times[bio];
97 |
98 | rqs[rq] -= 1;
99 | if(rqs[rq] == 0) {
100 | speculate(specs[rq], probe_print(bio));
101 | speculate(specs[rq], "----------\n");
102 | commit(specs[rq]);
103 |
104 | delete specs[rq];
105 | }
106 | }
--------------------------------------------------------------------------------
/scripts/stap/tapset/lstat.stp:
--------------------------------------------------------------------------------
1 | probe lstat = kernel.function("sys_lstat64").return ? ,
2 | kernel.function("sys32_lstat64").return ? {
3 | filename = user_string($filename);
4 | size = user_uint64(& @cast($statbuf, "struct stat64")->st_size);
5 | }
6 |
7 | probe lstat = kernel.function("sys_newlstat").return ? {
8 | filename = user_string($filename);
9 | %( arch == "x86_64"
10 | %? size = user_uint64(& @cast($statbuf, "struct stat")->st_size);
11 | %: size = user_uint32(& @cast($statbuf, "struct stat")->st_size);
12 | %)
13 | }
--------------------------------------------------------------------------------
/scripts/stap/topphp.stp:
--------------------------------------------------------------------------------
1 | @define httpd %( "/usr/local/apache2/bin/httpd" %)
2 | @define libphp5 %( "/usr/local/apache2/modules/libphp5.so" %)
3 |
4 | global rquri, starttime, functime;
5 |
6 | probe process(@httpd).mark("process__request__entry") {
7 | rquri[tid()] = user_string($arg2);
8 | }
9 |
10 | probe process(@libphp5).mark("function__entry") {
11 | starttime[tid()] = gettimeofday_ns();
12 | }
13 |
14 | probe process(@libphp5).mark("function__return") {
15 | if(starttime[tid()] == 0) next;
16 |
17 | func = user_string($arg4) . user_string($arg5) . user_string($arg1);
18 | functime[func, rquri[tid()]] <<< (gettimeofday_ns() - starttime[tid()]);
19 | }
20 |
21 | probe end {
22 | foreach([func, uri] in functime) {
23 | printf("%40s %32s %8d %d\n", func, uri,
24 | @count(functime[func, uri]), @avg(functime[func, uri]));
25 | }
26 | }
--------------------------------------------------------------------------------
/scripts/stap/web.stp:
--------------------------------------------------------------------------------
1 | @define httpd %( "/usr/local/apache2/bin/httpd" %)
2 | @define libphp5 %( "/usr/local/apache2/modules/libphp5.so" %)
3 | @define mysqld %( "/usr/local/mysql/bin/mysqld" %)
4 |
5 | global parsequery;
6 | global execquery;
7 |
8 | function basename:string(s:string) {
9 | len = strlen(s)
10 | i = len
11 |
12 | while(i > 0) {
13 | /* 47 is code for '/' */
14 | if(stringat(s, i - 1) == 47)
15 | return substr(s, i, len - i);
16 |
17 | --i;
18 | }
19 |
20 | return s;
21 | }
22 |
23 | probe process(@httpd).mark("internal__redirect") {
24 | printf("[httpd] redirect\t'%s' -> '%s'\n",
25 | user_string($arg1), user_string($arg2));
26 | }
27 |
28 | probe process(@httpd).mark("read__request__entry") {
29 | printf("[httpd] read-request\n");
30 | }
31 |
32 | probe process(@httpd).mark("read__request__success") {
33 | servername = ($arg4) ? user_string($arg4) : "???";
34 |
35 | printf("[httpd] read-request\t%s %s %s [status: %d]\n",
36 | user_string($arg2), servername, user_string($arg3), $arg5);
37 | }
38 |
39 | probe process(@httpd).mark("process__request__entry") {
40 | printf("[httpd] process-request\t'%s'\n", user_string($arg2));
41 | }
42 |
43 | probe process(@httpd).mark("process__request__return") {
44 | printf("[httpd] process-request\t'%s' access-status: %d\n",
45 | user_string($arg2), $arg3);
46 | }
47 |
48 | probe process(@libphp5).mark("request__startup"),
49 | process(@libphp5).mark("request__shutdown") {
50 | printf("[ PHP ] %s\n\t%s '%s' file: %s \n", pn(), user_string($arg3),
51 | user_string($arg2), user_string($arg1));
52 | }
53 |
54 | probe process(@libphp5).mark("function__entry"),
55 | process(@libphp5).mark("function__return") {
56 | printf("[ PHP ] %s\n\t%s%s%s file: %s:%d \n", pn(),
57 | user_string($arg4), user_string($arg5), user_string($arg1),
58 | basename(user_string($arg2)), $arg3);
59 | }
60 |
61 | probe process(@mysqld).mark("query__parse__start") {
62 | parsequery[tid()] = user_string_n($arg1, 1024);
63 | }
64 |
65 | probe process(@mysqld).mark("query__parse__done") {
66 | printf("[MySQL] query-parse\t'%s' status: %d\n", parsequery[tid()], $arg1);
67 | }
68 |
69 | probe process(@mysqld).mark("query__exec__start") {
70 | execquery[tid()] = user_string_n($arg1, 1024);
71 | }
72 |
73 | probe process(@mysqld).mark("query__exec__done") {
74 | printf("[MySQL] query-exec\t'%s' status: %d\n", execquery[tid()], $arg1);
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/scripts/stap/wqtrace.stp:
--------------------------------------------------------------------------------
1 | probe kernel.function("prepare_to_wait*"),
2 | kernel.function("add_wait_queue*") {
3 | if(pid() == stp_pid()) next;
4 |
5 | state = -1;
6 | if(@defined($state))
7 | state = $state;
8 |
9 | printf("[%d]%s %s:%s\n\twq head: %p wq: %p\n",
10 | pid(), execname(), symname(caller_addr()),
11 | probefunc(), $q, $wait);
12 | printf("\ttsk: %p state: %x func: %s\n",
13 | $wait->private, state, symname($wait->func));
14 | }
15 |
16 | probe kernel.function("wait_for_completion*") {
17 | if(pid() == stp_pid()) next;
18 |
19 | timeout = 0;
20 | if(@defined($timeout))
21 | timeout = $timeout;
22 |
23 | printf("[%d]%s %s:%s\n\tcompletion: %pwq head: %p timeout: %d\n",
24 | pid(), execname(), symname(caller_addr()),
25 | probefunc(), $x, &$x->wait, timeout);
26 | }
27 |
28 | probe kernel.function("wait_for_completion*").return {
29 | if(pid() == stp_pid()) next;
30 |
31 | printf("[%d]%s %s:%s\n\tcompletion: %p\n",
32 | pid(), execname(), symname(caller_addr()), probefunc(), $x);
33 | }
34 |
35 | probe kernel.function("finish_wait"),
36 | kernel.function("remove_wait_queue") {
37 | if(pid() == stp_pid()) next;
38 |
39 | printf("[%d]%s %s:%s\n\twq head: %p wq: %p\n",
40 | pid(), execname(), symname(caller_addr()),
41 | probefunc(), $q, $wait);
42 | }
43 |
44 | probe kernel.function("complete"),
45 | kernel.function("complete_all") {
46 | if(pid() == stp_pid()) next;
47 |
48 | printf("[%d]%s %s:%s\n\tcompletion: %p wq head: %p\n",
49 | pid(), execname(), symname(caller_addr()),
50 | probefunc(), $x, &$x->wait);
51 | }
52 |
53 | probe kernel.function("__wake_up"),
54 | kernel.function("__wake_up_locked*"),
55 | kernel.function("__wake_up_sync*") {
56 | if(pid() == stp_pid()) next;
57 |
58 | nr = -1
59 | if(@defined($nr_exclusive))
60 | nr = $nr_exclusive;
61 | if(@defined($nr))
62 | nr = $nr;
63 |
64 | printf("[%d]%s %s:%s\n\twq head: %p state: %p nr: %d\n",
65 | pid(), execname(), symname(caller_addr()),
66 | probefunc(), $q, $mode, nr);
67 | }
68 |
--------------------------------------------------------------------------------
/scripts/stap/wstat.stp:
--------------------------------------------------------------------------------
1 | global wstat;
2 |
3 | probe syscall.write {
4 | wstat[pid(), execname(), fd] <<< count;
5 | }
6 |
7 | probe timer.s(1) {
8 | printf("%5s %12s %3s %7s %7s\n",
9 | "PID", "EXECNAME", "FD", "OPS", "KBYTES");
10 |
11 | foreach([pid+, execname, fd] in wstat) {
12 | printf("%5d %12s %3d %7u %7u\n",
13 | pid, execname, fd, @count(wstat),
14 | @sum(wstat) / 1024);
15 | }
16 |
17 | delete wstat;
18 | }
19 |
--------------------------------------------------------------------------------
/tsdoc/gen-cheatsheet.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from tsdoc.page import MarkdownPage
5 | from tsdoc.blocks.html import HTMLPrinter
6 | from tsdoc.blocks.pdf import PDFPrinter, CheatSheetTemplate
7 |
8 | # Main code
9 | _ = sys.argv.pop(0)
10 | page_path = sys.argv.pop(0)
11 | out_path = sys.argv.pop(0)
12 |
13 | # Destination dir
14 | doc_dir = os.path.dirname(page_path)
15 |
16 | if out_path.endswith('.pdf'):
17 | printer = PDFPrinter(False, CheatSheetTemplate)
18 | elif out_path.endswith('.html'):
19 | printer = HTMLPrinter(os.getenv('TSDOC_HTML_TEMPLATE'))
20 |
21 | page = MarkdownPage(page_path)
22 | page.header = os.getenv('TSDOC_HEADER')
23 | page.docspace = None
24 |
25 | with open(out_path, 'wb') as outf:
26 | if printer.single_doc:
27 | printer.do_print_pages(outf, page.header, [page])
28 | else:
29 | printer.do_print(outf, page.header, page)
30 |
31 |
--------------------------------------------------------------------------------
/tsdoc/gen-doc.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from collections import defaultdict, OrderedDict
5 |
6 | from tsdoc import TSDoc
7 | from tsdoc.page import MarkdownPage, IndexPage
8 |
9 | from tsdoc.blocks import Link
10 | from tsdoc.blocks.markdown import MarkdownPrinter
11 | from tsdoc.blocks.html import HTMLPrinter
12 | from tsdoc.blocks.latex import LatexPrinter
13 | from tsdoc.blocks.pdf import PDFPrinter
14 | from tsdoc.blocks.epub import EpubPrinter
15 |
16 | # Main code
17 | _ = sys.argv.pop(0)
18 | index_path = sys.argv.pop(0)
19 |
20 | # Destination dir
21 | doc_dir = os.path.dirname(index_path)
22 |
23 | # Output format
24 | doc_format = os.getenv('TSDOC_FORMAT', 'html')
25 | doc_header = os.getenv('TSDOC_HEADER', '')
26 | verbose = os.getenv('TSDOC_VERBOSE', None) is not None
27 |
28 | if doc_format == 'html':
29 | doc_suffix = '.html'
30 | printer = HTMLPrinter(os.getenv('TSDOC_HTML_TEMPLATE'))
31 | elif doc_format == 'markdown':
32 | doc_suffix = '.out.md'
33 | printer = MarkdownPrinter()
34 | elif doc_format == 'latex':
35 | doc_suffix = '.tex'
36 | printer = LatexPrinter()
37 | elif doc_format == 'pdf':
38 | doc_suffix = '.pdf'
39 | printer = PDFPrinter()
40 | elif doc_format == 'epub':
41 | doc_suffix = '.epub'
42 | printer = EpubPrinter()
43 | else:
44 | raise ValueError("Invalid documentation format '%s'" % doc_format)
45 |
46 | pages = defaultdict(OrderedDict)
47 | tsdoc_pages = []
48 |
49 | if verbose:
50 | print 'Parsing ',
51 |
52 | for page_path in sys.argv:
53 | page_name = os.path.basename(page_path)
54 | print page_name,
55 | if page_path.endswith('.md'):
56 | page = MarkdownPage(page_path)
57 |
58 | pages[page.docspace][page.name] = page
59 |
60 | if verbose:
61 | print '\nProcessing',
62 |
63 | for page in tsdoc_pages:
64 | print '%s/%s' % (page.docspace, page.name),
65 | page.process()
66 |
67 | if verbose:
68 | print '\nBuilding index...'
69 |
70 | # Build indexes and Cross-References
71 | index_page = IndexPage(index_path, doc_header, pages)
72 | index_page.generate(printer, doc_dir, doc_suffix)
--------------------------------------------------------------------------------
/tsdoc/tsdoc/blocks/markdown.py:
--------------------------------------------------------------------------------
1 | import string
2 |
3 | from tsdoc.blocks import *
4 |
5 | class MarkdownPrinter(Printer):
6 | single_doc = False
7 |
8 | def __init__(self):
9 | pass
10 |
11 | def do_print(self, stream, header, page):
12 | self.stream = stream
13 | for block in page:
14 | self._print_block(block)
15 |
16 | def _md_filter(self, block, s):
17 | if isinstance(block, Code):
18 | return s
19 |
20 | s = s.replace('_', '\\_')
21 | s = s.replace('*', '\\*')
22 |
23 | return s
24 |
25 | def _last_newline(self, text):
26 | for char in reversed(text):
27 | if char not in string.whitespace:
28 | return False
29 |
30 | if char == '\n':
31 | return True
32 |
33 | return False
34 |
35 | def _print_block(self, block):
36 | if isinstance(block, Paragraph):
37 | self.stream.write('\n')
38 | if isinstance(block, Code):
39 | self.stream.write('\n```\n')
40 | elif isinstance(block, ListEntry):
41 | self.stream.write(' ' * block.level + ' * ')
42 |
43 | text = ''
44 | for part in block:
45 | if isinstance(part, Block):
46 | self._print_block(part)
47 | else:
48 | prefix = ''
49 | suffix = ''
50 |
51 | if isinstance(part, Header):
52 | prefix = '#' * part.size + ' '
53 | suffix = '\n'
54 | elif isinstance(part, ItalicText):
55 | prefix = suffix = '_'
56 | elif isinstance(part, BoldText):
57 | prefix = suffix = '**'
58 | elif isinstance(part, InlineCode):
59 | prefix = suffix = '`'
60 | elif isinstance(part, Reference):
61 | prefix = '['
62 | suffix = ']'
63 | elif isinstance(part, Link):
64 | prefix = '['
65 |
66 | if part.type == Link.INTERNAL:
67 | suffix = '][%s]' % part.where
68 | else:
69 | suffix = '](%s)' % part.where
70 |
71 | text = self._md_filter(block, str(part))
72 | text = prefix + text + suffix
73 |
74 | self.stream.write(text)
75 |
76 | if isinstance(block, ListEntry):
77 | if not self._last_newline(text):
78 | self.stream.write('\n')
79 | elif isinstance(block, Code):
80 | self.stream.write('\n```\n')
81 | if isinstance(block, Paragraph):
82 | self.stream.write('\n')
--------------------------------------------------------------------------------
/tsload/SConstruct:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from SCons.Action import ActionFactory
4 |
5 | PathJoin = os.path.join
6 | PathBaseName = os.path.basename
7 | PathExists = os.path.exists
8 |
9 | from SCons.Errors import StopError
10 |
11 | # Setup path to TSLoad
12 | AddOption('--with-tsload', dest='tsload', action="store",
13 | default=PathJoin('/home/myaut/univer/tsload/agent/build/tsload-0.2.a1-linux2', 'share/tsload/devel'),
14 | metavar='DIR', help='Path to tsload development directory')
15 |
16 | if not GetOption('tsload') or not PathExists(GetOption('tsload')):
17 | raise StopError('Provide path to tsload by specifying --with-tsload option')
18 |
19 | env = DefaultEnvironment(ENV = {'PATH': os.environ['PATH']})
20 |
21 | env['TSLOAD_DEVEL_PATH'] = GetOption('tsload')
22 | env['TSPROJECT'] = 'file_opener'
23 | env['TSVERSION'] = '0.1'
24 | env['TSNAME'] = env['TSPROJECT'] + '-' + env['TSVERSION']
25 |
26 | env['TSEXTPATH'] = Dir('#').abspath
27 |
28 | env['VERBOSE_BUILD'] = ['cmdline']
29 |
30 | SConscript(PathJoin(env['TSLOAD_DEVEL_PATH'], 'SConscript.ext.py'), 'env')
31 |
32 | # ------------
33 | # MODULES
34 |
35 | modules = ['file_opener', 'proc_starter']
36 |
37 | for mod in modules:
38 | variant_dir = env.BuildDir(PathJoin('file_opener', mod))
39 |
40 | SConscript(PathJoin(mod, 'SConscript'), 'env',
41 | variant_dir = variant_dir)
--------------------------------------------------------------------------------
/tsload/file_opener/.ctime_cache:
--------------------------------------------------------------------------------
1 | modsrc.c.in 1421059608
2 | modsrc.h.in 1421059608
3 | SConscript.in 1421059608
4 | SConstruct.in 1421059608
5 |
--------------------------------------------------------------------------------
/tsload/file_opener/SConscript:
--------------------------------------------------------------------------------
1 | from pathutil import *
2 |
3 | target = 'file_opener'
4 |
5 | Import('env')
6 |
7 | mod = env.Clone()
8 | file_opener = mod.Module('load', target)
9 |
10 | experiment_json = File('experiment.json')
11 |
12 | mod.Depends(file_opener, [experiment_json])
13 |
14 | install_path = PathJoin(mod['INSTALL_VAR'], target)
15 | mod.InstallTarget(target, install_path, experiment_json)
--------------------------------------------------------------------------------
/tsload/file_opener/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file_opener",
3 | "steps": {
4 | "open": {
5 | "num_steps": 20,
6 | "num_requests": 100
7 | }
8 | },
9 | "threadpools": {
10 | "tp_open" : {
11 | "num_threads": 2,
12 | "quantum": 1000000000,
13 | "disp": {
14 | "type": "round-robin"
15 | }
16 | }
17 | },
18 | "workloads": {
19 | "open": {
20 | "wltype": "file_opener",
21 | "threadpool": "tp_open",
22 | "rqsched" : {
23 | "type": "iat",
24 | "distribution": "exponential"
25 | },
26 | "params": {
27 | "root_dir": "/tmp/fopen1",
28 | "created_files": 480,
29 | "max_files": 1024,
30 | "file": { "randgen": { "class": "lcg" } },
31 | "create": {
32 | "randgen": { "class": "lcg" },
33 | "pmap" : [
34 | { "value" : true, "probability" : 0.3 },
35 | { "value" : false, "probability" : 0.7 }
36 | ]
37 | }
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/tsload/file_opener/include/file_opener.h:
--------------------------------------------------------------------------------
1 | #ifndef FILE_OPENER_H_
2 | #define FILE_OPENER_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | struct file_opener_workload {
9 | char root_dir[1024];
10 | wlp_integer_t created_files;
11 | wlp_integer_t max_files;
12 |
13 | };
14 |
15 | struct file_opener_request {
16 | wlp_integer_t file;
17 | wlp_bool_t create;
18 |
19 | };
20 | #endif /* BUSY_WAIT_H_ */
21 |
22 |
--------------------------------------------------------------------------------
/tsload/file_opener/modinfo.cfg:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file_opener",
3 | "wlt_class": [ "fs_op" ],
4 | "has_step": true,
5 | "params": {
6 | "root_dir": {
7 | "_type": "tsload.wlparam.WLParamString",
8 | "description": "Directory where files would be created / deleted",
9 | "len": 1024
10 | },
11 | "created_files": {
12 | "_type": "tsload.wlparam.WLParamInteger",
13 | "description": "Number of files that would be preliminary created"
14 | },
15 | "max_files": {
16 | "_type": "tsload.wlparam.WLParamInteger",
17 | "description": "Maximum number of files"
18 | },
19 | "file": {
20 | "_type": "tsload.wlparam.WLParamInteger",
21 | "request": true,
22 | "description": "ID of file"
23 | },
24 | "create": {
25 | "_type": "tsload.wlparam.WLParamBoolean",
26 | "request": true,
27 | "description": "Set O_CREAT flag"
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/tsload/proc_starter/.ctime_cache:
--------------------------------------------------------------------------------
1 | modsrc.c.in 1421244766
2 | modsrc.h.in 1421244766
3 | SConscript.in 1421244766
4 |
--------------------------------------------------------------------------------
/tsload/proc_starter/SConscript:
--------------------------------------------------------------------------------
1 | from pathutil import *
2 | import subprocess
3 |
4 | target = 'proc_starter'
5 |
6 | Import('env')
7 |
8 | mod = env.Clone()
9 |
10 | proc_starter = mod.Module('load', target)
11 |
12 | experiment_json = File('experiment.json')
13 |
14 | mod.Depends(proc_starter, [experiment_json])
15 |
16 | install_path = PathJoin(mod['INSTALL_VAR'], target)
17 | mod.InstallTarget(target, install_path, experiment_json)
--------------------------------------------------------------------------------
/tsload/proc_starter/experiment.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "proc_starter",
3 | "steps": {
4 | "open": {
5 | "num_steps": 10,
6 | "num_requests": 150
7 | }
8 | },
9 | "threadpools": {
10 | "tp_proc" : {
11 | "num_threads": 12,
12 | "quantum": 1000000000,
13 | "disp": {
14 | "type": "round-robin"
15 | }
16 | }
17 | },
18 | "workloads": {
19 | "open": {
20 | "wltype": "proc_starter",
21 | "threadpool": "tp_proc",
22 | "rqsched" : {
23 | "type": "iat",
24 | "distribution": "exponential"
25 | },
26 | "params": {
27 | "num_shells": 12,
28 | "command": {
29 | "randgen": { "class": "lcg" },
30 | "pmap" : [
31 | { "probability": 0.4,
32 | "value": "cat /etc/passwd"
33 | },
34 | { "probability": 0.2,
35 | "value": "ls /var"
36 | },
37 | { "probability": 0.1,
38 | "value": "ls /usr/lib"
39 | },
40 | { "probability": 0.2,
41 | "value": "bash -c 'exit 0'"
42 | },
43 | { "probability": 0.1,
44 | "value": "gcc -v"
45 | }
46 | ]
47 | }
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/tsload/proc_starter/include/proc_starter.h:
--------------------------------------------------------------------------------
1 | #ifndef PROC_STARTER_H_
2 | #define PROC_STARTER_H_
3 |
4 | #include
5 |
6 | #include
7 |
8 | #include
9 |
10 | struct proc_starter_workload {
11 | wlp_integer_t num_shells;
12 | char shell[1024];
13 | };
14 |
15 | struct proc_starter_data {
16 | squeue_t sq;
17 | };
18 |
19 | struct proc_starter_request {
20 | char command[512];
21 |
22 | };
23 | #endif /* BUSY_WAIT_H_ */
24 |
25 |
--------------------------------------------------------------------------------
/tsload/proc_starter/include/shell.h:
--------------------------------------------------------------------------------
1 | #ifndef SHELL_H_
2 | #define SHELL_H_
3 |
4 | #define DEV_PTS_NAMELEN 32
5 | #define DEV_PTY_MASTER "/dev/ptmx"
6 |
7 | #define SHELL_BUF_SIZE 2048
8 | #define SHELL_WATERMARK 128
9 |
10 | #define SHELL_SETSID_ERROR 1
11 | #define SHELL_SLAVE_OPEN_ERROR 2
12 | #define SHELL_CLOSE_MASTER_ERROR 3
13 | #define SHELL_CLOSE_SLAVE_ERROR 4
14 | #define SHELL_DUP2_ERROR 5
15 | #define SHELL_EXECVE_ERROR 6
16 | #define SHELL_SIGRESET_ERROR 7
17 | #define SHELL_MKTERM_ERROR 8
18 |
19 | #define SHELL_TRACE_PTRS 0x01
20 | #define SHELL_TRACE_BUFS 0x02
21 |
22 | typedef struct pt_shell {
23 | int sh_pty;
24 | int sh_pid;
25 |
26 | char sh_pt_name[DEV_PTS_NAMELEN];
27 |
28 | char* sh_buffer;
29 | size_t sh_buf_size;
30 |
31 | char* sh_start;
32 | char* sh_end;
33 |
34 | /* Variables used only in sh_create() */
35 | int sh_pt_slave;
36 | /* Status PIPE. We couldn't track errors on child directly because
37 | * logging uses mutexes, and using they from forked processes is dangerous */
38 | int sh_status_pipes[2];
39 | } ps_shell_t;
40 |
41 | ps_shell_t* sh_create(const char* filename, char* const argv[],
42 | char* const envp[]);
43 | void sh_destroy(ps_shell_t* sh);
44 |
45 | char* sh_expect(ps_shell_t* sh, const char* line);
46 |
47 | #endif /* SHELL_H_ */
48 |
--------------------------------------------------------------------------------
/tsload/proc_starter/modinfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "proc_starter",
3 | "wlt_class": [ "os" ],
4 | "has_data": true,
5 | "params": {
6 | "num_shells": {
7 | "_type": "tsload.wlparam.WLParamInteger",
8 | "description": "Number of pre-forked shells. It is recommended to set this value to number of threads in threadpool.",
9 | "min": 1,
10 | "max": 1000
11 | },
12 | "shell": {
13 | "_type": "tsload.wlparam.WLParamString",
14 | "optional": true,
15 | "default": "/usr/bin/sh",
16 | "description": "Path to pre-forked shell",
17 | "len": 1024
18 | },
19 | "command": {
20 | "_type": "tsload.wlparam.WLParamString",
21 | "request": true,
22 | "description": "Command to be executed in request",
23 | "len": 512
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------