<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5799246</id><updated>2012-01-13T15:47:11.687Z</updated><category term='mathematics'/><category term='reiser4'/><category term='file system'/><category term='kernel'/><category term='programming'/><title type='text'>a very occasional diary</title><subtitle type='html'>nondescript</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.cofault.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.cofault.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>61</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5799246.post-2148242483437445819</id><published>2011-12-24T21:50:00.000Z</published><updated>2011-12-24T21:59:07.656Z</updated><title type='text'>Cue a key</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div align="justify"&gt;
There is a typical problem with &lt;a href="http://en.wikipedia.org/wiki/Emacs"&gt;Emacs&lt;/a&gt; experienced by people frequently switching between different keyboard mappings, for example, to work with non ASCII languages: fundamental Emacs keyboard shortcuts (and one has to invoke them &lt;em&gt;a lot&lt;/em&gt; to use Emacs efficiently) all use ASCII keys. For example, when I want to save my work, while entering some Russian text, I have to do something like &lt;tt&gt;Alt-Space&lt;/tt&gt; (switch to the US keyboard layout) &lt;tt&gt;&lt;a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Save-Commands.html#index-C_002dx-s-845"&gt;Control-x-s&lt;/a&gt;&lt;/tt&gt; (a Emacs shortcut to save buffers) &lt;tt&gt;Alt-Space&lt;/tt&gt; (shift back to the Cyrillic keyboard layout). Switching out and back to a keyboard layout only to tap a short key sequence is really annoying.&lt;br /&gt;
&lt;br /&gt;
Two solutions are usually proposed:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Duplicate standard key sequences in other keyboard layouts. For example,&lt;br /&gt;
&lt;pre&gt;(global-set-key [(control ?ч ?ы)] 'save-some-buffers)
&lt;/pre&gt;
expression in &lt;tt&gt;.emacs&lt;/tt&gt; binds &lt;tt&gt;Control-ч-ы&lt;/tt&gt; to the same command as &lt;tt&gt;Control-x-s&lt;/tt&gt; is usually bound. This eliminates the need to switch layout, because &lt;tt&gt;ч&lt;/tt&gt;-&lt;tt&gt;x&lt;/tt&gt; (and &lt;tt&gt;ы&lt;/tt&gt;-&lt;tt&gt;s&lt;/tt&gt;) symbols are located on the same key (in &lt;a href="http://en.wikipedia.org/wiki/QWERTY"&gt;QWERTY&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/JCUKEN"&gt;JCUKEN&lt;/a&gt; layouts respectively).&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Another solution employs the fact that Emacs is &lt;a href="https://www.google.com/search?q=Emacs+is+a+great+operating+system.+If+only+it+had+a+decent+text+editor"&gt;a complete operating system&lt;/a&gt; and, therefore, has its own keyboard layout switching mechanism (bound to &lt;tt&gt;Control-\&lt;/tt&gt; by default). When this mechanism is used, Emacs re-interprets normals keys according to its internal layout, so that typing &lt;tt&gt;s&lt;/tt&gt; inserts &lt;tt&gt;ы&lt;/tt&gt; when in internal Russian mode, while all command sequences continue to work independently of layout. The mere idea of having &lt;em&gt;two&lt;/em&gt; independent layout switching mechanisms and two associated keyboard state indicators is clearly ugly beyond words (except for people who use Emacs as their &lt;tt&gt;/sbin/init&lt;/tt&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
Fortunately, there is another way:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;; Map Modifier-CyrillicLetter to the underlying Modifier-LatinLetter, so that
; control sequences can be used when keyboard mapping is changed outside of
; Emacs.
;
; For this to work correctly, .emacs must be encoded in the default coding
; system.
;
(mapcar* 
 (lambda (r e) ; R and E are matching Russian and English keysyms
   ; iterate over modifiers
   (mapc (lambda (mod)
    (define-key input-decode-map 
      (vector (list mod r)) (vector (list mod e))))
  '(control meta super hyper))
   ; finally, if Russian key maps nowhere, remap it to the English key without
   ; any modifiers
   (define-key local-function-key-map (vector r) (vector e)))
   "йцукенгшщзхъфывапролджэячсмитьбю"
   "qwertyuiop[]asdfghjkl;'zxcvbnm,.")
&lt;/pre&gt;
&lt;br /&gt;
(Inspired by a cryptic remark about "Translation Keymaps" in &lt;a href="http://vorotylo.livejournal.com/"&gt;vvv&lt;/a&gt;'s &lt;a href="https://github.com/vvv/dotfiles/blob/master/.emacs"&gt;.emacs&lt;/a&gt;.)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-2148242483437445819?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/2148242483437445819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=2148242483437445819' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/2148242483437445819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/2148242483437445819'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2011/12/cue-key.html' title='Cue a key'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4937279264799577372</id><published>2011-12-09T01:00:00.000Z</published><updated>2011-12-08T21:08:59.895Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Unintentionally yours.</title><content type='html'>&lt;div dir="ltr" style="text-align: justify;" trbidi="on"&gt;&lt;script src="https://d3eoax9i5htok0.cloudfront.net/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;
    
&lt;/script&gt;&lt;br /&gt;
&lt;h2&gt;Extension.&lt;/h2&gt;&lt;br /&gt;
This post is about &lt;a href="http://en.wikipedia.org/wiki/Set_theory"&gt;set theory&lt;/a&gt;, which is a framework to reason about collections, elements and membership.&lt;br /&gt;
&lt;br /&gt;
We start with a informal and naïve outline, which is (very loosely) based on a &lt;a href="http://en.wikipedia.org/wiki/Von_Neumann-Bernays-G%C3%B6del_set_theory"&gt;Godel-Bernays&lt;/a&gt; version of set theory. This theory is about sets (collections) which contain elements, which can in turn be sets. When a set \(X\) contains an element \(t\), it is written \(t\in X\). &lt;br /&gt;
&lt;br /&gt;
First, set equality has to be defined:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;E0 &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_extensionality"&gt;Axiom of extensionality&lt;/a&gt;&lt;/b&gt;:&lt;br /&gt;
$$X = Y \equiv (t \in X \equiv t \in Y)$$&lt;br /&gt;
(Here \(\equiv\) is a logical equivalence, pronounced "&lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;if and only if&lt;/a&gt;".) This axiom means that sets are equal if and only if they have the same elements. (In this and following formulae, free variables are implicitly &lt;a href="http://en.wikipedia.org/wiki/Universal_quantification"&gt;universally quantified&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
Subsets are defined by \(X \subseteq Y \equiv (t\in X \Rightarrow t\in Y)\), that is, X is a subset of Y when every element of X is also an element of Y. It's easy to check that \(X = Y \equiv (X\subseteq Y \wedge Y\subseteq X)\), where \(\wedge\) means "and".&lt;br /&gt;
&lt;br /&gt;
Next, a way to build new sets is needed:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;E1 &lt;a href="http://en.wikipedia.org/wiki/Set-builder_notation"&gt;Axiom of (extensional) comprehension&lt;/a&gt;&lt;/b&gt;:&lt;br /&gt;
$$t \in \{u \mid P(u)\} \equiv P(t)$$&lt;br /&gt;
This axiom introduces a "set-builder notation" \(\{u \mid P(u) \}\) and states that \(\{u \mid P(u) \}\) is exactly the set of all \(t\) such that \(P(t)\) holds.&lt;br /&gt;
&lt;br /&gt;
Now, there is already enough machinery for two famous collections to be immediately constructed: &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Empty_set"&gt;empty set&lt;/a&gt;&lt;/b&gt;, \(\varnothing = \{t \mid false \}\), which contains no elements, and &lt;a href="http://en.wikipedia.org/wiki/Universe_(mathematics)"&gt;the collection of all sets&lt;/a&gt;: \(U = \{t \mid true \}\), which contains all possible elements.&lt;br /&gt;
&lt;br /&gt;
With these axioms, conventional set operations can be defined:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Singleton_(mathematics)"&gt;singleton&lt;/a&gt;: \(\{t\} = \{u\mid u = t\}\), for each \(t\) a singleton set \(\{t\}\) can be constructed that contains \(t\) as its only element. Note that \(t\in\{t\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Union_(set_theory)"&gt;union&lt;/a&gt;: \(X\cup Y = \{t\mid t \in X \vee t \in Y\}\) (\(\vee\) means "or")&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Intersection_(set_theory)"&gt;intersection&lt;/a&gt;: \(X\cap Y = \{t\mid t\in X \wedge t\in Y\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Complement_(set_theory)"&gt;complement&lt;/a&gt;: \(\complement X = \{t \mid t \notin X\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;(unordered) &lt;a href="http://en.wikipedia.org/wiki/Unordered_pair"&gt;pair&lt;/a&gt;: \(\{t,u\} = \{t\}\cup\{u\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Ordered_pair"&gt;ordered pair&lt;/a&gt;: \((t,u) = \{t, \{t, u\}\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Power_set"&gt;power set&lt;/a&gt;: \(\mathfrak{P}(X) = \{t \mid t \subseteq X\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
From here, one can build hierarchical sets, representing all traditional mathematical structures, starting with natural numbers: &lt;br /&gt;
&lt;br /&gt;
$$0 = \varnothing, 1 = \{0\}, 2 = \{0, 1\}, \ldots n + 1 = \{0, \ldots, n\}, \ldots$$&lt;br /&gt;
&lt;br /&gt;
then integers, rationals, reals, &lt;i&gt;&amp;amp;c.&lt;/i&gt;, adding more axioms (of &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_infinity"&gt;infinity&lt;/a&gt;, of &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_regularity"&gt;foundation&lt;/a&gt;, of &lt;a href="http://en.wikipedia.org/wiki/Axiom_schema_of_replacement"&gt;replacement&lt;/a&gt;, &lt;i&gt;&amp;amp;c&lt;/i&gt;.) along the way.&lt;br /&gt;
&lt;br /&gt;
It was discovered quite early that this system is not entirely satisfactory. First defect is that it is impossible to have elements which are not sets themselves. For example, one would like to talk about a "set of all inhabited planets in the Solar system". Elements of this set (planets) are not sets, they are called &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Urelement"&gt;ur-elements&lt;/a&gt;&lt;/i&gt;. Unfortunately, the axiom of extensionality makes all ur-elements equal to the empty set. Note, that this indicates that the axiom of extensionality doesn't work well with sets that have very few (none) elements. This was never considered a problem, because all sets of interest to mathematics can be constructed without ur-elements.&lt;br /&gt;
&lt;br /&gt;
Another, more serious drawback, arises in the area of very large sets: existence of a set \(\{t\mid t\notin t\}\) directly leads to a contradiction known as &lt;a href="http://en.wikipedia.org/wiki/Russell's_paradox"&gt;Russel's paradox&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Among several methods to deal with this, one separates sets into two types: "smaller" collections which are continued to be called "sets" and "proper classes", which are collections so large that they cannot be a member of any collection. Axiom of comprehension is carefully modified so that set-builder never produces a collection having some class as its element. In this setup Russel's paradox becomes a theorem: \(\{t\mid t\notin t\}\) is a proper class.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Intention.&lt;/h2&gt;&lt;br /&gt;
The axiom of extensionality states that sets are equal when they &lt;em&gt;contain&lt;/em&gt; the same elements. What would happen, if set theory were based on a dual notion of &lt;em&gt;intentional equality&lt;/em&gt; (which will be denoted by \(\sim\) to tell it from extensional one), where sets are equal when they are &lt;em&gt;contained&lt;/em&gt; in the same collections?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;I0 Axiom of intensionality&lt;/b&gt;:&lt;br /&gt;
$$X \sim Y \equiv (X \in t \equiv Y\in t)$$&lt;br /&gt;
This looks bizarre: for any "normal" set \(X\) a collection of all sets containing \(X\) as element is unmanageably huge. But as a matter of fact, intentional equality is much older than extensional, it is variously known as &lt;em&gt;Leibniz's law&lt;/em&gt;, &lt;a href="http://en.wikipedia.org/wiki/Identity_of_indiscernibles"&gt;identity of indiscernibles&lt;/a&gt; and, in less enlightened age, as &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;duck typing&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
There is a nice symmetry: while intensional equality myopically confuses small sets (ur-elements), extensional equality cannot tell very large collections (proper classes) from each other, because they are not members of anything and, therefore, intentionally equal.&lt;br /&gt;
&lt;br /&gt;
The whole extensional theory buildup can be mirrored easily by moving things around \(\in\) sign:&lt;br /&gt;
&lt;br /&gt;
Intensional subsets: \(X \unlhd Y \equiv (X\in t \Rightarrow Y\in t)\)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;I1 Axiom of intensional comprehension (incomprehension)&lt;/b&gt;:&lt;br /&gt;
$$[u \mid P(u)]\in t \equiv P(t)$$&lt;br /&gt;
&lt;br /&gt;
And associated operations:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;uniqum (or should it have been "s-&lt;i&gt;ex&lt;/i&gt;-gleton?): \([t] = [u\mid u \sim t]\), note that \([t]\in t\).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional union: \(X\triangledown Y = [t\mid X \in t \vee Y \in t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional intersection: \(X\triangle Y = [t\mid X \in t \wedge Y \in t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional complement: \(\Game X = [t \mid X \notin t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional pair: \([t,u] = [t]\triangledown [u]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional ordered pair: \(&amp;lt;t,u&amp;gt; = [t, [t, u]]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional power set: \(\mathfrak{J}(X) = [t \mid X \unlhd t\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
What do all these things &lt;em&gt;mean&lt;/em&gt;? In extensional world, a set is a container, where elements are stored. In intensional world, a set is a &lt;em&gt;property&lt;/em&gt;, which other sets might or might not enjoy. If \(t\) has property \(P\), it is written as \(t\in P\). In the traditional notation, \(P\) is called a &lt;em&gt;predicate&lt;/em&gt; and \(t\in P\) is written as \(P(t)\). The axiom of intentional equality claims that sets are equal when they have exactly the same properties (quite natural, right?). \(X\) is an intentional subset of \(Y\) when \(Y\) has all properties of \(X\) and perhaps some more (this looks like a nice way to express &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;LSP&lt;/a&gt;). Intentional comprehension \([u \mid P(u)]\) is a set having exactly all properties \(t\) for which \(P(t)\) holds and no other properties. Intentional union of two sets is a set having properties of either and their intentional intersection is a set having properties of both, &lt;i&gt;&amp;amp;c&lt;/i&gt;. Uniqum \([P]\) is &lt;em&gt;the&lt;/em&gt; set that has property \(P\) and no other properties.&lt;br /&gt;
&lt;br /&gt;
Because intensional theory is a perfect dual of extensional nothing interesting is obtained by repeating extensional construction, for example, by building "intensional natural numbers" as &lt;br /&gt;
&lt;br /&gt;
$$0' = U, 1' = [0'], 2' = [0', 1'], \ldots (n + 1)' = [0', \ldots, n'], \ldots$$&lt;br /&gt;
&lt;br /&gt;
What is more interesting, is how intensional and extensional twins meet. With some filial affection it seems:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;by uniqum property \([\varnothing] \in\varnothing\), which contradicts the definition of \(\varnothing\), also&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;set \([t\mid false]\) is not a member of any set (perhaps it's a proper class) and set \([t\mid true]\) is a member of every set, which is strange;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;a set of which a singleton can be formed has very shallow intentional structure. Indeed:&lt;br /&gt;
&lt;table border="0" bordercolor="#ffffff" style="background-color:" cellpadding="3" cellspacing="3"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x \unlhd y\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ definition of intensional subset }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x\in t \Rightarrow y\in t\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\Rightarrow\)&lt;/td&gt;&lt;td&gt;{ substitute \(\{x\}\) for \(t\)}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x\in \{x\} \Rightarrow y\in \{x\}\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ \(x\in \{x\}\) is true by the singleton property, &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Modus_ponens"&gt;modus ponens&lt;/a&gt;&lt;/i&gt; }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(y\in \{x\}\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ the singleton property, again }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x = y\)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/ul&gt;To get rid of contradictions and to allow intensional and extensional sets to co-exist peacefully, domains on which singleton and uniqum operations are defined must be narrowed.  To be continued. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4937279264799577372?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4937279264799577372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4937279264799577372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4937279264799577372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4937279264799577372'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2011/11/unintentionally-yours.html' title='Unintentionally yours.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1841531294338939775</id><published>2010-12-29T19:42:00.002Z</published><updated>2010-12-29T19:44:23.574Z</updated><title type='text'>From the traveller diary.</title><content type='html'>Note to oneself: general anaesthesia is a very efficient cure for jet lag.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1841531294338939775?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1841531294338939775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1841531294338939775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1841531294338939775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1841531294338939775'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/12/traveller-diary.html' title='From the traveller diary.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-5216923215068280821</id><published>2010-02-18T19:20:00.000Z</published><updated>2010-02-18T19:20:02.520Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'></title><content type='html'>An obscure generalisation: a redundancy domain should be transversal (better yet, orthogonal) to a potential failure vector. Hello, &lt;a href="http://en.wikipedia.org/wiki/Narendra_Karmarkar"&gt;Karmarkar&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-5216923215068280821?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/5216923215068280821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=5216923215068280821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5216923215068280821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5216923215068280821'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/02/obscure-generalisation-redundancy.html' title=''/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-9082152881386341264</id><published>2010-02-04T21:20:00.004Z</published><updated>2010-03-10T20:50:23.805Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>The Hunt for Addi(c)tive Monster 2.</title><content type='html'>&lt;div style="text-align: justify;"&gt;
In the &lt;a href="http://www.cofault.com/2010/01/hunt-for-addictive-monster.html"&gt;previous post&lt;/a&gt;, we were looking for&amp;nbsp;&lt;i&gt;a monster&lt;/i&gt;—a nonlinear additive function. We found that such a function is extremely pathological: it is nowhere locally monotone, nowhere continuous and nowhere locally bounded. Worse than that, it's easy to prove that the graph of a monster is &lt;a href="http://en.wikipedia.org/wiki/Dense_set"&gt;dense&lt;/a&gt; in &lt;img border="0" src="http://l.wordpress.com/latex.php?latex={{\mathbb{R} \times \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, that is, for every &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt;, an arbitrary neighborhood of &lt;i&gt;x&lt;/i&gt; contains a point that monster sends arbitrarily close to &lt;i&gt;y&lt;/i&gt;.&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;
Recall &lt;a href="http://www.cofault.com/2010/01/hunt-for-addictive-monster.html#construction-0"&gt;our attempt&lt;/a&gt; to construct a monster. Any additive function is linear on any &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set and is fully determined on this set by a value it has in any single of its points. Our Direchlet function derived monster failed (or rather fell) because the slopes an additive function has on different &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-sets are not independent. Indeed, given that &lt;i&gt;f&lt;/i&gt; has a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_1}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot\alpha_1}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; and a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot\alpha_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, it has to have a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_1 %2B k_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot(\alpha_1 %2B \alpha_2)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. This shows a way to construct a monster: one has to find a collection &lt;i&gt;B&lt;/i&gt; of real numbers &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{r_1, r_2, \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; such that (i) every real number can be represented as a sum &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot r_1 %2B q_2\cdot r_2 %2B \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;, with rational coefficients &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1, q_2, \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; of which only finite number is non-zero (so that the sum is defined) and (ii) that such representation is unique. Then one can select arbitrary values on elements of &lt;i&gt;B&lt;/i&gt; and take moster's value on &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot r_1 %2b q_2\cdot r_2 %2b \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; to be &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot f(r_1) %2b q_2\cdot f(r_2) %2b \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, which is well-defined thanks to (ii).&lt;br /&gt;
&lt;br /&gt;
Looks familiar? It should be: the definition of &lt;i&gt;B&lt;/i&gt; is exactly the definition of &lt;a href="http://en.wikipedia.org/wiki/Basis_(linear_algebra)"&gt;a basis&lt;/a&gt; of a vector space. Real numbers can be added to each other and multiplied by rationals and, therefore, form a vector space over&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. This space is very different from a usual one-dimensional vector space real numbers form over&amp;nbsp;&lt;img src="http://l.wordpress.com/latex.php?latex={{\mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; (&lt;i&gt;i.e.&lt;/i&gt;, over themselves).&lt;br /&gt;
&lt;br /&gt;
After a streak of bad and unlikely properties that a monster has, we now got something positive: a monster exists if and only if&amp;nbsp;&lt;img src="http://l.wordpress.com/latex.php?latex={{\mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;as a vector space over&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;has a basis. Does it?&lt;br /&gt;
&lt;br /&gt;
But of course. Any vector space has a basis—this is a general theorem almost immediately following from the &lt;a href="http://en.wikipedia.org/wiki/Zorn's_lemma"&gt;Zorn's lemma&lt;/a&gt;. The basis we are looking for even got a name of its own: &lt;a href="http://mathworld.wolfram.com/HamelBasis.html"&gt;&lt;i&gt;Hamel basis&lt;/i&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
At last we stumbled across the whole family on monsters. Specifically, there exists a set &lt;img src="http://l.wordpress.com/latex.php?latex={{B \subset \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;and a function &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q : \mathbb{R}\times B \rightarrow \mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; such that every real number r can be uniquely represented as&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{r = \displaystyle\sum_{b\in B}q(r, b)\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/div&gt;
&lt;br /&gt;
where only finite number of &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q(r, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;are non-zero for a given &lt;i&gt;r&lt;/i&gt;. From this it immediately follows that &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q(r_1 %2b r_2, b) = q(r_1, b) %2b q(r_2, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;.&lt;br /&gt;
&lt;br /&gt;
Take an arbitrary function &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0 : B \rightarrow \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, and define&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r) = \displaystyle\sum_{b\in B} f_0(b)\cdot q(r, b)\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;&lt;/div&gt;
Now,&lt;br /&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r_1) %2b f(r_2) = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot q(r_1, b)\cdot b %2b \displaystyle\sum_{b\in B} f_0(b)\cdot q(r_2, b)\cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot\left(q(r_1, b) %2b q(r_2, b)\right)\cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;div style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot q(r_1 %2b r_2, b) \cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r_1 %2b r_2)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
that is,&amp;nbsp;&lt;i&gt;f&lt;/i&gt; is additive. Intuitively,&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0(b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; is a slope &lt;i&gt;f&lt;/i&gt; has at the &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. &lt;i&gt;f&lt;/i&gt; is linear if and only if &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; is a constant function, in all other cases &lt;i&gt;f&lt;/i&gt; is a monster. If one takes &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0 : b \mapsto 1/b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, then&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r) = \displaystyle\sum_{b\in B} q(r, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
is an especially weird monster function: it takes only rational values!&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
Note that almost all additive functions are, after all, monsters—only very small sub-set of them is linear.&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-9082152881386341264?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/9082152881386341264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=9082152881386341264' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/9082152881386341264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/9082152881386341264'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/02/hunt-for-addictive-monster-2.html' title='The Hunt for Addi(c)tive Monster 2.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-7287619472314268722</id><published>2010-01-12T15:12:00.042Z</published><updated>2010-02-04T21:21:28.618Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>The Hunt for Addi(c)tive Monster</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;div class="separator" style="clear: both; text-align: justify;"&gt;
This is another spurious post about mathematics that happened instead
of something more useful. Let's talk about one of the most common
mathematical objects: a &lt;a href="http://en.wikipedia.org/wiki/Function_%28mathematics%29"&gt;function&lt;/a&gt;&amp;nbsp;that maps&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Real_number"&gt;real numbers&lt;/a&gt; (&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;) to real numbers. We shall call such a function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; &lt;i&gt;additive&lt;/i&gt; &lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;iff&lt;/a&gt;&amp;nbsp;for any real &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="f(a + b) = f(a) + f(b)" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520y%2520%2520fx%2520%2520fy.gif" /&gt;
&lt;br /&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
This is a natural and simple condition. Well-known examples of additive functions are provided by &lt;i&gt;linear&lt;/i&gt; functions &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520x%2520mapsto%2520k%2520cdot%2520x.gif" /&gt;, where &lt;i&gt;k&lt;/i&gt; is called &lt;i&gt;a slope&lt;/i&gt;.
Are there other, non-linear additive functions? And if so, how do they
look like? A bit of thinking convinces one that a non-linear additive
function is not trivial to find. In fact, as we shall show below,
should such a function exist, it would exhibit extremely weird
features. Hence, we shall call a non-linear additive function &lt;i&gt;a monster&lt;/i&gt;.
In the following, some properties that a monster function has to
possess are investigated, until a monster is cornered either out of
existence or into an example. Out of misplaced spite we shall use &lt;a href="http://en.wikipedia.org/wiki/%28%CE%B5,_%CE%B4%29-definition_of_limit"&gt;&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon-delta.gif" /&gt; technique&lt;/a&gt; in some proofs.&lt;br /&gt;
&lt;br /&gt;
First, some trivial remarks about the collection of all additive functions (which will be denoted &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt;).&lt;br /&gt;
&lt;br /&gt;
If &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;, &lt;img align="middle" alt="g : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeg%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;&amp;nbsp;are two additive functions and &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%2520in%2520mathbbR.gif" /&gt; — an arbitrary real number, then &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizefg.gif" /&gt;, &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize-f.gif" /&gt; and &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%2520cdot%2520f.gif" /&gt; are additive. This means that additive functions form a &lt;a href="http://en.wikipedia.org/wiki/Vector_space"&gt;vector space&lt;/a&gt; over field &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt; with constant zero additive function as a &lt;a href="http://en.wikipedia.org/wiki/Zero_vector"&gt;zero vector&lt;/a&gt;. This vector space is a sub-space of a vector space of all functions from &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt; to &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;. Product of two additive functions is not in general additive (when it is?), but their composition is:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%252520circ%252520gx%252520%252520y%252520%252520fgx%252520%25252.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Unfortunately, composition is not compatible with scalars (&lt;i&gt;i.e.&lt;/i&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%252520cdot%252520f%252520circ%252520beta%252520cdot%2525.gif" /&gt;), and additive functions are not an&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Algebra_over_a_field"&gt;algebra over a field&lt;/a&gt;&amp;nbsp;&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;, but see below.&lt;br /&gt;
&lt;br /&gt;
Looking at an individual additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;, it's easy to see that even it is not clear that it must be linear everywhere, there are some subsets of &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;&amp;nbsp;on which is obviously has to be linear:&lt;br /&gt;
&lt;br /&gt;
For any real number &lt;i&gt;x&lt;/i&gt; and for any natural number &lt;i&gt;n&lt;/i&gt;,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefncdot%252520x%252520%252520fx%252520%252520cdots%252520%252520x.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
that is, restriction of &lt;i&gt;f&lt;/i&gt; to any subset &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizexcdot%2520mathbbN%2520subset%2520mathbbR.gif" /&gt; is linear and in particular, &lt;i&gt;f&lt;/i&gt; is linear when restricted to the natural numbers. Specifically, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef0%252520%252520f2%252520cdot%2525200%252520%2525202%252520cdot%25.gif" /&gt;, from this&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef-x%252520%252520f-x%252520%252520fx%252520-%252520fx%252520%25252.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
Similarly,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeffrac1n%252520cdot%252520x%252520%252520frac1n%252520cdot%2525.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
Combining these results, for any rational number &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeq%2520%2520fracnm%2520in%2520mathbbQ.gif" /&gt;,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefq%252520cdot%252520x%252520%252520ffracnm%252520cdot%252520x%25.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
That is, &lt;i&gt;f&lt;/i&gt; is linear when restricted to any subset of the form &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizex%2520cdot%2520mathbbQ%2520subset%2520mathbbR.gif" /&gt;. We shall call such subset &lt;i&gt;a &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Notice that we just proved that composition of linear functions is
compatible with multiplication on rational scalars (see above), so that
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt; is an algebra over &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;.&lt;br /&gt;
&lt;br /&gt;
Having briefly looked over the landscape of &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt;,
let's start converging on our prey. How bad a monster function must be?
A linear function has all the good qualities one might wish for: it is &lt;a href="http://en.wikipedia.org/wiki/Monotonic_function"&gt;monotonic&lt;/a&gt;,&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Continuous_function"&gt;continuous&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Differentiable_function"&gt;differentiable&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Smooth_function"&gt;smooth&lt;/a&gt;,
it's even... linear. Which of these it enjoys together with a monster?
It's intuitively very unlikely that an additive, but non-linear
function might happen to be differentiable, so let's start with
checking continuity.&lt;br /&gt;
&lt;br /&gt;
Statement 0. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is continuous at point &lt;i&gt;x&lt;/i&gt;, then&amp;nbsp;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520x%2520cdot%2520f1.gif" /&gt;.&lt;br /&gt;
&lt;blockquote&gt;
Indeed,&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizebeginarraycclfx%252520%252520%252520%252520%252520%252520mboxt.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
That is, an additive function is linear everywhere it is continuous.
This means that a monster must be&amp;nbsp;discontinuous&amp;nbsp;at least in
one point. Note that linear functions are precisely everywhere
continuous additive functions. Can a monster function
be&amp;nbsp;discontinuous&amp;nbsp;in a single point? Or, even, can it be
continuous &lt;i&gt;somewhere&lt;/i&gt;? It is easy to show that property of additivity constrains structure of sets on which function is continuous severely:&lt;br /&gt;
&lt;br /&gt;
Statement 1. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is continuous at point &lt;i&gt;x&lt;/i&gt;, it is linear.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Take an arbitrary non-zero point &lt;i&gt;y&lt;/i&gt;. By statement 0,&amp;nbsp;&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520x%2520cdot%2520f1.gif" /&gt;. By definition of continuity at &lt;i&gt;x&lt;/i&gt;,&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeforall%252520epsilon%252520%2525200%252520rightarrow%252520e.gif" /&gt;&amp;nbsp;,&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
For any natural &lt;i&gt;n&lt;/i&gt;, take&amp;nbsp;&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%2520%2520frac1n%2520%25200.gif" /&gt;&amp;nbsp;and find a rational number &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize%252520q_ncdoty%252520-%252520x%252520%252520%252520mindelta%252.gif" /&gt;. Such &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; always exists due to density of rationals. By choice of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; we have:&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize-frac1n%252520%252520q_n%252520cdoty%252520-%252520x%252520%2525.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
and by the &lt;a href="http://en.wikipedia.org/wiki/Squeeze_theorem"&gt;sandwich theorem&lt;/a&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; converges:&amp;nbsp;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizelim_ntoinftyq_n%2520%2520fracxy.gif" /&gt;. Now, again, by choice of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt;: &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize%252520q_n%252520cdot%252520y%252520-%252520x%252520%252520%252520.gif" /&gt;, so &lt;i&gt;y&lt;/i&gt;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; satisfies the condition on &lt;i&gt;x'&lt;/i&gt; above and &lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="\epsilon = \frac1n &amp;gt; |f(q_n \cdot y) - f(x)| = |q_n \cdot f(y) - x \cdot f(1)|" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%252520%252520frac1n%252520%252520fq_n%252520cdot%25252.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
Taking the (obviously existing)&amp;nbsp;limits of both sides of this inequality,&amp;nbsp;one gets&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="f(y) = \frac{x \cdot f(1)}{\lim_{n\to\infty}q_n} = \frac{x \cdot f(1)}{x/y} = y \cdot f(1)" border="0" src="http://linuxhacker.ru/~nikita/images/add/y%2520%2520y%2520cdot%2520f1.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
The case of y being 0 is trivial.&lt;/blockquote&gt;
Oh. A monster function cannot be continuous even at a single point—it
is discontinuous everywhere. Additive functions are divided into two
separated classes: nice, everywhere continuous linear functions and
&amp;nbsp;unseemly, everywhere discontinuous monsters. (We still don't know
whether the latter class is populated, though.) Our expectations of
capturing a monster and placing a trophy in a hall must be adjusted:
even if we prove that a monster exists and construct it, an idea of
drawing its &lt;a href="http://en.wikipedia.org/wiki/Graph_of_a_function"&gt;graph&lt;/a&gt; must be abandoned—it's too ugly to be depicted.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="" name="construction-0"&gt;&lt;/a&gt;Let's think for a moment how a monster might look like. Every additive function is linear on any &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set. If it is linear with the same slope on all &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets—it is linear. A monster must have different slopes for at least some of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets. In the simplest case there is a single &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set
with a slope different from the others. There is a famous function (a
freshman nightmare and examiner delight) immediately coming into a
mind: the &lt;a href="http://en.wikipedia.org/wiki/Nowhere_continuous_function"&gt;Dirichlet function&lt;/a&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeD%2520%2520mathbbR%2520rightarrow%2520mathbbZ_2.gif" /&gt;, equal 1 on rationals and 0 on irrationals. The function &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsized%2520%2520x%2520mapsto%2520x%2520cdot%2520Dx.gif" /&gt;&amp;nbsp;is
identity (and hence linear) when restricted to rationals and is
constant zero (again linear) when restricted to irrationals. Looks
promising? Unfortunately,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize0%252520%252520d1%252520%252520pi%252520neq%252520d1%252520%252520.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Also, &lt;i&gt;d&lt;/i&gt; is continuous at 0 and thus disqualified
from&amp;nbsp;monstrousness&amp;nbsp;by statement 1. This shot into darkness
missed. At at least we now see that not only monster must have
different slopes at different &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets, but these slopes must be selected to be consistent with addition.&lt;br /&gt;
&lt;br /&gt;
Let's return to monster properties. A monster function is discontinuous everywhere, but how badly is it discontinuous? &lt;i&gt;E.g.&lt;/i&gt;, a function is &lt;a href="http://en.wikipedia.org/wiki/Local_boundedness"&gt;locally bounded&lt;/a&gt;
at every point where it is continuous. A monster is continuous nowhere,
but is it still locally bounded anywhere or somewhere? In a way similar
to statement 1 it's easy to prove the&lt;br /&gt;
&lt;br /&gt;
Statement 2. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is bounded on any segment [&lt;i&gt;a&lt;/i&gt;, &lt;i&gt;b&lt;/i&gt;], &lt;i&gt;a &amp;lt; b&lt;/i&gt;, then it is linear.&lt;br /&gt;
&lt;blockquote&gt;
First, by using that &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizef-x%2520%2520-fx.gif" /&gt;, &amp;nbsp;and restricting segment if necessary, one can assume that &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize0%2520%2520a%2520%2520b.gif" /&gt;, and &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeforall%252520x%252520in%252520a%252520b%252520rightarrow%25252.gif" /&gt;.&lt;/blockquote&gt;
&lt;blockquote&gt;
Let's prove that &lt;i&gt;f&lt;/i&gt; is continuous at 0, then it will be linear by the statement 1. For arbitrary &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%2520%25200.gif" /&gt;, let's select &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizedelta.gif" /&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize0%2520%2520delta%2520%2520fracaCcdotepsilon.gif" /&gt;&amp;nbsp;(this choice is a typical magician hat trick of &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon-delta.gif" /&gt; proofs). For arbitrary &lt;i&gt;x&lt;/i&gt; from the &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizedelta.gif" /&gt;-vicinity of 0 there is always a rational &lt;i&gt;q&lt;/i&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizea%2520%2520qcdot%2520x%2520%2520b.gif" /&gt;. For such &lt;i&gt;q&lt;/i&gt; we have:&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeq%252520%252520fracax%252520%252520fracadelta%252520%252520fra.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
on the other hand, we have:&lt;br /&gt;
&lt;blockquote&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizebeginarrayrclfx%252520%252520%252520%252520ffracqcdot%252520.gif" /&gt;&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
establishing that &lt;i&gt;f&lt;/i&gt; is continuous at 0.&lt;/blockquote&gt;
This indicates that a monster is not just a bad function, it's a very
bad function, that takes arbitrarily large absolute values in
arbitrarily small segments. Too bad. As a byproduct, a monster cannot
be monotonic on any segment, because a function monotonic on [&lt;i&gt;a&lt;/i&gt;, &lt;i&gt;b&lt;/i&gt;] is bounded there: &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefa%2520leq%2520fx%2520leq%2520fb.gif" /&gt;&amp;nbsp;(for increasing function, similarly for decreasing).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.cofault.com/2010/02/hunt-for-addictive-monster-2.html"&gt;continued&lt;/a&gt;.&lt;b&gt;]&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-7287619472314268722?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/7287619472314268722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=7287619472314268722' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/7287619472314268722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/7287619472314268722'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/01/hunt-for-addictive-monster.html' title='The Hunt for Addi(c)tive Monster'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4071479957601685895</id><published>2009-09-20T14:33:00.002Z</published><updated>2009-09-20T14:40:17.241Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><title type='text'>To the Lustre Group people</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://picasaweb.google.com/danilov/A4#5382922663089670802" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_QCNNSTdukHs/SrP7pGLcCpI/AAAAAAAAJPM/5JgnpmiXZRo/s320/CIMG0076.JPG" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
With the best wishes to Sun^WOracle, and &lt;i&gt;sapienti &lt;a href="http://wiki.lustre.org/images/6/66/CLIO-TOI.pdf"&gt;sat&lt;/a&gt;&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4071479957601685895?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4071479957601685895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4071479957601685895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4071479957601685895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4071479957601685895'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/09/to-lustre-group-people.html' title='To the Lustre Group people'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QCNNSTdukHs/SrP7pGLcCpI/AAAAAAAAJPM/5JgnpmiXZRo/s72-c/CIMG0076.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4955873462769947276</id><published>2009-08-21T11:07:00.015Z</published><updated>2009-08-21T13:25:24.403Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>a trivial exercise.</title><content type='html'>&lt;div style="text-align: justify;"&gt;Let's find a sum&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=6156d5fba9e2bc73ae25f65e9922d4f0"&gt;&lt;/center&gt;&lt;br&gt;

There is a well-know standard way, that I managed to recall eventually. Given that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=aedff0aa4c12833656b0d7be385d2088" STYLE="vertical-align: middle;" ALT="$${1 \over n(n+2)} = {1 \over 2}\cdot \left({1\over n} - {1\over n+2}\right)$$" HEIGHT="51" WIDTH="259"&gt;&lt;/center&gt;&lt;br&gt;

the sum can be re-written as&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=f658ebfb6b0015852558bacf8b3c00bc" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = \sum_{n=1}^\infty {1 \over 2}\left({1\over n} - {1\over n+2}\right) = {1\over 2}\left({1\over 1} - {1\over 3} + {1\over 2} - {1\over 4} + {1\over 3} - {1\over 5} + {1\over 4} - {1\over 6} \cdots\right)$$" height="58" width="725" /&gt;&lt;/center&gt;&lt;br&gt;

with almost all terms canceling each other, leaving&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=367cfc1e89df5edaa1eab5127a97aba8" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = {1\over 2}\left(1 + {1\over 2}\right) = {3\over 4}$$" height="58" width="285" /&gt;&lt;/center&gt;&lt;br&gt;

While this is easy to check, very little help is given on understanding how to arrive to the solution in the first place. Indeed, the first (and crucial) step is a rabbit pulled &lt;span style="font-style: italic;"&gt;sans motif&lt;/span&gt; out of a conjurer hat. The solution, fortunately, can be found in a more systematic fashion, by a relatively generic method. Enter &lt;a href="http://en.wikipedia.org/wiki/Generating_function"&gt;generating functions&lt;/a&gt;.&lt;br&gt;&lt;br&gt;

First, introduce a function&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=d00d8c3c9f58dfcad4996ada9a7ed186" style="vertical-align: middle;" alt="$$f(t) = \sum_{n=1}^\infty {t^{n + 1}\over n}$$" height="58" width="140" /&gt;&lt;/center&gt;&lt;br&gt;

The series on the right converge absolutely when |t| &lt; 1, so one can define&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=5191d5a25430c7bac0bf6e83016e832d" STYLE="vertical-align: middle;" ALT="$$g(t) = \int f(t) dt = \int \sum_{n=1}^\infty {t^{n + 1}\over n} = \sum_{n=1}^\infty \int {t^{n + 1}\over n} = \sum_{n=1}^\infty {t^{n + 2}\over {n(n+2)}} + C$$" HEIGHT="58" WIDTH="589"&gt;&lt;/center&gt;&lt;br&gt;

with the sum in question being&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=7240522421194f419404885930786b43" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = g(1) - C = g(1) - g(0)$$" height="58" width="349" /&gt;&lt;/center&gt;&lt;br&gt;

Definition of the &lt;span style="font-style: italic;"&gt;g&lt;/span&gt; function follows immediately from the form of the original sum, and there is a limited set of operations (integration, differentiation, &lt;span style="font-style: italic;"&gt;etc&lt;/span&gt;.) applicable to &lt;span style="font-style: italic;"&gt;g&lt;/span&gt; to produce &lt;span style="font-style: italic;"&gt;f&lt;/span&gt;.&lt;br&gt;&lt;br&gt;

The rest is more or less automatic. Note that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=4b213b85278134477d35774075284944" style="vertical-align: middle;" alt="$$- ln(1 - t) = t + {t^2\over 2} + {t^3\over 3} + \cdots$$" height="47" width="271" /&gt;&lt;/center&gt;&lt;br&gt;

so that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=7453e9ff6f54f3b8e15ced8a66ad4226" STYLE="vertical-align: middle;" ALT="$$f(t) = t^2 + {t^3\over 2} + {t^4\over 3} + \cdots = - t \cdot ln(1-t)$$" HEIGHT="47" WIDTH="366"&gt;&lt;/center&gt;&lt;br&gt;

therefore&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=0dbc086a7c888a1d0b7659f5710d385e" style="vertical-align: middle;" alt="$$g(t) = - \int t \cdot ln(1-t) dt = \cdots = {1\over 4} (1 - t)^2 - {1\over 2} (1 - t)^2 ln(1 - t) + (1 - t) ln(1 - t) + t + C$$" height="47" width="814" /&gt;&lt;/center&gt;&lt;br&gt;

where the integral is standard. Now,&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=659b1184e90d24dd18dc7a78e334c329" style="vertical-align: middle;" alt="$$g(1) - g(0) = 1 - {1\over 4} = {3\over 4}$$" height="42" width="219" /&gt;&lt;/center&gt;&lt;br&gt;

&lt;span style="font-style: italic;"&gt;Voilà&lt;/span&gt;!&lt;br&gt;&lt;br&gt;

And just to check that things are not too far askew, a sub-exercise in a &lt;a href="http://en.wikipedia.org/wiki/Tacit_programming"&gt;pointless programming&lt;/a&gt;:&lt;br&gt;
&lt;pre&gt;
&lt;b&gt;scala&gt;&lt;/b&gt; (1 to 10000).map(x =&gt; 1.0/(x*(x+2))).reduceLeft(_+_)
&lt;b&gt;res0: Double = 0.749900014997506&lt;/b&gt;
&lt;/pre&gt;&lt;br&gt;&lt;br&gt;

PS: of course this post is an exercise in &lt;a href="http://spiny.at.org/%7Ecola/tex2img"&gt;tex2img&lt;/a&gt; usage.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4955873462769947276?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4955873462769947276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4955873462769947276' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4955873462769947276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4955873462769947276'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/08/trivial-exercise.html' title='a trivial exercise.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1995448071384193322</id><published>2009-04-23T09:23:00.006Z</published><updated>2009-06-05T10:57:13.803Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.</title><content type='html'>&lt;div style="text-align: justify;"&gt;[This is an old and never finished draft. HTML produced by &lt;a href="http://www.methods.co.nz/asciidoc/"&gt;asciidoc&lt;/a&gt;.]

   &lt;/div&gt;&lt;h1&gt;A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.&lt;/h1&gt;&lt;div style="text-align: justify;"&gt;
   2009.04.22
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Nikita Danilov &amp;lt;danilov@gmail.com&amp;gt;
     v0.1, September 2007&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Abstract&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A proposal is made to modify C language to make
     accessing &lt;tt&gt;struct&lt;/tt&gt; and &lt;tt&gt;union&lt;/tt&gt; fields
     (&lt;tt&gt;s.f&lt;/tt&gt; and &lt;tt&gt;p-&amp;gt;f&lt;/tt&gt;) more flexible. To that end,
     instead of considering &lt;tt&gt;.f&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;f&lt;/tt&gt; as
     families of unary postfix operators applicable to the values
     of &lt;tt&gt;struct&lt;/tt&gt; and &lt;tt&gt;union&lt;/tt&gt; types and pointers,
     respectively, fields are treated as values or special &lt;em&gt;member
     designator types&lt;/em&gt; introduced for this purpose,
     while &lt;tt&gt;.&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;&lt;/tt&gt; become binary
     operators. Typing rules for the field types and examples of
     their usage are proposed.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;References in square brackets are to the ISO/IEC C standard.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Overview&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;One of the important advantages of C language is the (relative)
     simplicity and cleanness of its memory model: data structures
     eventually boil down to the “objects” [3.15],
     addressable by pointers and contiguous in address space. This is
     most evident in the case of array subscription [6.5.2.1], that
     is &lt;em&gt;defined&lt;/em&gt; through the pointer arithmetic:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;[6.5.2.1] International Standard ISO/IEC 9899&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       Semantics

 [#2] A postfix expression followed by an expression in square
 brackets [] is a subscripted designation of an element of an
 array object.  The definition of the subscript operator [] is
 that E1[E2] is identical to (*((E1)+(E2))).  Because of the
 conversion rules that apply to the binary + operator, if E1 is
 an array object (equivalently, a pointer to the initial element
 of an array object) and E2 is an integer, E1[E2] designates the
 E2-th element of E1 (counting from zero).
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Not only array subscription thus defined makes arrays and pointers
     mostly equivalent, but it also inherits all the good properties of
     addition (commutativity, associativity), and automatically defines the
     meaning of multidimensional arrays.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Another fundamental operation, structure and union member
     de-reference [6.5.2.3] is not, however, similarly reduced to the
     pointer manipulations. Instead, the “Types” [6.2.5]
     section defines types of a sequential (structure) and overlapping
     (union) sets of member objects, and operations are later described
     abstractly as accessing member objects:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;[6.5.2.3] International Standard ISO/IEC 9899&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 Semantics
 
 [#3] A postfix expression followed by the . operator and  an
 identifier  designates  a  member  of  a  structure or union
 object.  The value is that of the named member,  and  is  an
 lvalue  if  the first expression is an lvalue.
     &lt;/pre&gt;
 &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;The inflexibility of this definition is clear when compared
     with what one can do with the arrays: C permits nothing similar
     to &lt;tt&gt;foo(a0,a1)[bar(b0.b1)]&lt;/tt&gt; for structure and union
     member access. Standard &lt;tt&gt;offsetof()&lt;/tt&gt; macro [7.17]
     converts member designator to an integer constant, equal to the
     member byte offset within the structure of union, but no support
     at the syntax level exists.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;We propose to introduce a family of scalar types representing
     member designators and to define &lt;tt&gt;.&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;&lt;/tt&gt;
     operations in terms of values of these types, in fact, in the
     way very similar to how array subscription is defined.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;The perceived advantages of this are:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;ul style="text-align: justify;"&gt;
     &lt;li&gt;
   array and structure operations become similar;
     &lt;/li&gt;
     &lt;li&gt;
 structure and union operations are reduced to (already defined)
 pointer manipulations, improving orthogonality of the language;
     &lt;/li&gt;
     &lt;li&gt;
 more generic structure-like data types are introduced for free, see
 below.
     &lt;/li&gt;
   &lt;/ul&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Note that in some sense this is not a new development. Vintage C code
     fragments sport usage like&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;v6root/usr/sys/ken/iget.c&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 iupdat(p, tm)
  int *p;
  int *tm;
  {
         register *ip1, *ip2, *rp;
        int *bp, i;

        rp = p;
        if((rp-&amp;gt;i_flag&amp;amp;(IUPD|IACC)) != 0) {
         ...
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;indicating that member designators (&lt;tt&gt;i_flag&lt;/tt&gt; in this
     case, look at the &lt;em&gt;interesting&lt;/em&gt; declaration of &lt;tt&gt;rp&lt;/tt&gt;) weren't originally tied to a specific structure or union
     type. They were, in fact, existing by themselves in a special
     global namespace—a property that led to the custom of
     prefixing field names with a unique prefix.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Informal proposal&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A new derived type constructor &lt;tt&gt;-&amp;gt;&lt;/tt&gt; is introduced. A
   declarator&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       TYPE0 -&amp;gt; TYPE1
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;specifies a type of a member designator for a member object with a
     type &lt;tt&gt;TYPE1&lt;/tt&gt; in a type &lt;tt&gt;TYPE0&lt;/tt&gt;.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A declarator&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       TYPE0 -&amp;gt; TYPE1 :N:M
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;where N and M are integer constants, specifies a type of a
     member designator for a bit-field of a member object starting at
     Nth bit and containing M bits.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Values of any member designator type can be cast to int and
     back without loss of information, passed to and returned from
     the functions, etc. A declaration of the form&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       STRUCT-OR-UNION IDENTIFIER {
               TYPE0 FIELD0;
               TYPE1 FIELD1;
               ...
       };
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;implicitly defines constants of the corresponding member designator
     types for all members of STRUCT-OR-UNION IDENTIFIER type. Defined
     constants have values designating their eponymous structure of union
     members. For example,&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 struct F {
               int              F_x;
               float            F_y[10];
               void          *(*F_f)(int, struct F *);
               unsigned char    F_b:1;
 };
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;implicitly defines&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       const struct F -&amp;gt; int                        F_x;
       const struct F -&amp;gt; float[10]                  F_y;
       const struct F -&amp;gt; void *(*)(int, struct F *) F_f;
       const struct F -&amp;gt; unsigned char :X:1         F_b; /* for some X */
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;For any non bit-field member FIELD it holds that&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       offsetof(STRUCT-OR-UNION IDENTIFIER, FIELD) == (int)FIELD
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Following operations are defined on values of member designator
   types:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;ul style="text-align: justify;"&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E0&lt;/tt&gt; of type “pointer
   to &lt;tt&gt;T0&lt;/tt&gt;”, and an expression &lt;tt&gt;E1&lt;/tt&gt; of
   type &lt;tt&gt;T0 -&amp;gt; T1&lt;/tt&gt;, &lt;tt&gt;E0-&amp;gt;E1&lt;/tt&gt; is equivalent to
 &lt;/p&gt;
 &lt;div class="code"&gt;
   &lt;pre&gt;
           *(T1 *)(((char *)E0) + E1)
   &lt;/pre&gt;
 &lt;/div&gt;
 &lt;p&gt;where &lt;tt&gt;E1&lt;/tt&gt; is implicitly converted to an integer type;&lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E0&lt;/tt&gt; of type &lt;tt&gt;A -&amp;gt; B&lt;/tt&gt;
   and an expression E1 of type &lt;tt&gt;B -&amp;gt; C&lt;/tt&gt;,
   expression &lt;tt&gt;E0.E1&lt;/tt&gt; has type &lt;tt&gt;A -&amp;gt; C&lt;/tt&gt;, and
   corresponds to the member of B, viewed as a member of A;
 &lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E&lt;/tt&gt; of type &lt;tt&gt;A -&amp;gt; B&lt;/tt&gt;, a
   unary expression &lt;tt&gt;-E&lt;/tt&gt; has type &lt;tt&gt;B -&amp;gt; A&lt;/tt&gt;,
   and designates an instance of &lt;tt&gt;A&lt;/tt&gt; in which an
   instance of &lt;tt&gt;B&lt;/tt&gt; designated by &lt;tt&gt;E&lt;/tt&gt; is embedded;
 &lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   a compound assignment &lt;tt&gt;E0 -&amp;gt;= E1&lt;/tt&gt; is defined as an
   abbreviation for &lt;tt&gt;E0 = E0-&amp;gt;E1&lt;/tt&gt;, with E0 evaluated
   only once.
 &lt;/p&gt;
     &lt;/li&gt;
   &lt;/ul&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Examples&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;Example: Basic usage&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
struct F {
       int F_x;
};

struct G {
       int      G_y;
       struct F G_f;
};

void foo() {
       struct G  g;
       struct F *nested;

       printf("designators: %i %i %i\n", F_x, G_y, G_f);
       g.G_y = 1;     /* defined as *(g + G_y) = 1; */
       g.G_f.F_x = 2; /* defined as *(g + G_f.F_x) = 2; */
       nested = &amp;amp;g.G_f;
       /* nested-&amp;gt;(-G_f) is g */
       assert(nested-&amp;gt;(-G_f).G_y == 1);
       /* or... */
       assert(nested-&amp;gt;(-G_f.G_y) == 1);
}
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;Example: Searching for an item in a linked
   list&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;&lt;tt&gt;
struct list_link {
       struct list_link *ll_next;
}

struct list_item {
       struct list_link li_next;
       int               li_value;
};

struct list_link *search(struct list_link *s, int key) {
       for (; s &amp;amp;&amp;amp; s-&amp;gt;-li_next.li_value != key; s -&amp;gt;= li_next) {
              ;
       }
       return s;
}
     &lt;/tt&gt;&lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Note that foo-&amp;gt;-bar subsumes container_of() macro (as used in the
     Linux kernel).&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;C is traditionally used as a language for the system
     programming—a domain where one has often to deal with
     formatted data on the storage or network. As a typical example
     let's imagine a system that keeps formatted meta-data, e.g., a
     list of directory entries for a file system or index entries for
     a data-base in a block device block. Different devices have
     different block sizes, which means that in general case format
     of a device block cannot be described by a C structure
     type. With member designator types, however, something similar
     to the following can be done:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
/* variable sized device block */
typedef char * block_contents_t;

struct block_format {
       /* magic number at the beginning of the block */
       block_contents_t -&amp;gt; uint32_t bf_start_magic;
       /* array of keys in the index block, growing to the right */
       block_contents_t -&amp;gt; key_t[]  bf_keys;
       /* array of values, corresponding to the keys, growing to the left */
       block_contents_t -&amp;gt; val_t[]  bf_values;
       /* magic number at the end of the block */
       block_contents_t -&amp;gt; uint32_t bf_end_magic;
};

struct system_descriptor {
      ...
      struct block_format sd_format;
      ...
};

void init(struct system_descriptor *desc, int block_size) {
      switch (block_size) {
             case 512:
                    desc-&amp;gt;sd_format.bf_keys      = ...;
                    desc-&amp;gt;sd_format.bf_values    = ...;
                    desc-&amp;gt;sd_format.bf_end_magic = ...;
                    break;
             case 1024:
                    ...
      }
}

int block_search(struct system_descriptor *desc, block_contents_t block,
                key_t *key) {
       int i;

       assert(block-&amp;gt;(desc-&amp;gt;bf_start_magic) == START_MAGIC);
       assert(block-&amp;gt;(desc-&amp;gt;sd_format.bf_end_magic) == END_MAGIC);

       for (i = 0; i &amp;lt; NUM_KEYS; ++i) {
               if (key_cmp(&amp;amp;(block-&amp;gt;(desc-&amp;gt;sd_format.bf_keys))[i], key) {
                       ...
}
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Clearly, quite generic yet type-safe data structures can be
   built this way.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Problems&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Backward compatibility is broken because field names must be
     unique within a compilation unit now (as they have constants
     declared for them). This is “safe” violation of
     compatibility in that it doesn't change the semantics of an
     existing code silently.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Meaning of &lt;tt&gt;E0.E1&lt;/tt&gt; for a non-lvalue E0 is awkward to
     define.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1995448071384193322?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1995448071384193322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1995448071384193322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1995448071384193322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1995448071384193322'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/04/modest-proposal-for-generalizing-field.html' title='A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-636750832348992096</id><published>2009-03-25T14:20:00.005Z</published><updated>2009-03-25T14:37:54.129Z</updated><title type='text'>It _could_ be done</title><content type='html'>&lt;div align="justify"&gt;
&lt;blockquote&gt;&lt;a href="http://www.multicians.org/andre.html"&gt;The late André Bensoussan worked with me on the Multics [...]. We were working on a major change to the file system [...].&lt;br&gt;
&lt;br&gt;
André took on the job of design, implementation, and test of the VTOC manager. He started by sitting at his desk and drawing a lot of diagrams. I was the project coordinator, so I used to drop in on him and ask how things were going. "Still designing," he'd say. He wanted the diagrams to look beautiful and symmetrical as well as capturing all the state information. [...] I was glad when he finally began writing code. He wrote in pencil, at his desk, instead of using a terminal. [...]&lt;br&gt;
&lt;br&gt;
Finally André took his neat final pencil copy to a terminal and typed the whole program in. His first compilation attempt failed; he corrected three typos, tried again, and the code compiled. We bound it into the system and tried it out, and it worked the first time.&lt;br&gt;
&lt;br&gt;
In fact, the VTOC manager worked perfectly from then on. [...]&lt;br&gt;
&lt;br&gt;
How did André do this, with no tool but a pencil?&lt;/a&gt;&lt;/blockquote&gt;
&lt;br&gt;
Those people were programming operating system kernel that supported kernel level multi-threading and SMP (in 60s!), had most features UNIX kernels have now and some that no later operating system has, like transparent HSM. All under hardware constraints that would make modern washing machine to look like a super-computer. Of course they were thinking, &lt;span style="font-style:italic;"&gt;then&lt;/span&gt; typing.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-636750832348992096?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/636750832348992096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=636750832348992096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/636750832348992096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/636750832348992096'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/03/it-could-be-done.html' title='It _could_ be done'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4443857992164915740</id><published>2007-08-08T22:53:00.000Z</published><updated>2007-08-08T23:47:26.227Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Leisure pace of progress</title><content type='html'>Recently I found a paper in &lt;a href="http://acm.org"&gt;ACM Library&lt;/a&gt; describing two distributed file  systems with the following features:
&lt;ul&gt;
    &lt;li&gt;distributed read-write locking at the byte granularity;&lt;/li&gt;
    &lt;li&gt;user visible distributed transactions with isolation and roll-back;&lt;/li&gt;
    &lt;li&gt;capability based authentication;&lt;/li&gt;
    &lt;li&gt;files implemented as B-trees;&lt;/li&gt;
    &lt;li&gt;distributed garbage collection of unreferenced objects;&lt;/li&gt;
    &lt;li&gt;atomicity through COW (aka &lt;i&gt;shadow writes&lt;/i&gt;, aka &lt;i&gt;wandering logs&lt;/i&gt;);&lt;/li&gt;
    &lt;li&gt;intent logging of file system updates (hello, &lt;a href="http://en.wikipedia.org/wiki/Zfs"&gt;ZFS&lt;/a&gt;);&lt;/li&gt;
    &lt;li&gt;storage failure resilience methods, similar to ones in &lt;a href="http://marc.info/?l=linux-fsdevel&amp;m=117779868908188&amp;w=2"&gt;TileFS&lt;/a&gt;;&lt;/li&gt;
    &lt;li&gt;directories implemented as separate service, using the same interface as usual clients.&lt;/li&gt;
&lt;/ul&gt;
Quite impressive and obviously matched by nothing publicly available currently. How it happened that these marvels are not trumpeted about on every corner? Very simple: these systems were put in production &lt;em&gt;before 1981&lt;/em&gt;. AD, that is. Funny enough, one of them is even named &lt;a href="http://clusterfs.com"&gt;CFS&lt;/a&gt;.
&lt;hr&gt;
[0] James G. Mitchell, Jeremy Dion &lt;i&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=358475&amp;dl=ACM&amp;coll=portal"&gt;A comparison of two network-based file servers&lt;/a&gt;&lt;/i&gt;&lt;br&gt;
[1] Jeremy Dion &lt;i&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=850710&amp;dl=ACM&amp;coll=portal"&gt;The Cambridge File Server&lt;/a&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4443857992164915740?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4443857992164915740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4443857992164915740' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4443857992164915740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4443857992164915740'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/08/leisure-pace-of-progress.html' title='Leisure pace of progress'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1980494935123400459</id><published>2007-07-18T19:47:00.000Z</published><updated>2007-07-20T12:52:48.511Z</updated><title type='text'>Denver Zoo</title><content type='html'>How to keep a couple of linux kernel developers busy for a day:
&lt;center&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/st-Eloopvi4"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/st-Eloopvi4" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1980494935123400459?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1980494935123400459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1980494935123400459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1980494935123400459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1980494935123400459'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/07/denver-zoo.html' title='Denver Zoo'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-5448246024063252445</id><published>2007-06-27T21:20:00.001Z</published><updated>2007-06-27T21:39:29.347Z</updated><title type='text'>And now to the subject of death.</title><content type='html'>As little as I want to go into this, some misunderstanding is to be cleared.

Recent &lt;a href="http://www.wired.com/techbiz/people/magazine/15-07/ff_hansreiser?currentPage=1"&gt;interview&lt;/a&gt; [&lt;a href="http://developers.slashdot.org/article.pl?sid=07/06/27/129237&amp;from=rss"&gt;/.&lt;/a&gt;] with jailed Hans Reiser, by Joshua Davis, concludes with the following, presumably ominous paragraph:
&lt;blockquote&gt;While he launches into the intricacies of database science, I'm thinking, "Where is the front passenger seat of your car?" He has never explained this. It seems a fundamental hole in his defense. But he won't stop talking. When I try to interrupt, he insists I let him finish. It's as if the file system holds all the answers.

So I take the hint, and that night, in my office, I start scouring the 80,496 lines of the Reiser4 source code. Eventually I stumble across a passage that starts at line 78,077. It's not part of the program itself &amp;mdash; it's an annotation, a piece of non-executable text in plain English. It's there for the benefit of someone who has chosen to read this far into the code. The passage explains how memory structures are born, grow, and eventually die. It concludes: "Death is a complex process."&lt;/blockquote&gt;

The phrase in question is a part of a large top-of-the-file comment in znode.c, describing, indeed, among other things, a life-cycle of znode (Zam's node) data-structure.

But

&lt;ul&gt;
&lt;li&gt;It is not quoted verbatim (for a better effect, as one is left to assume). Grammatically incorrect original reads:
&lt;div class="code-title"&gt;znode.c&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
   ...
   5. His death.

   Death is complex process.

   When we irrevocably commit ourselves to decision to remove node from the
   tree, JNODE_HEARD_BANSHEE bit is set in zjnode.state of corresponding
   znode. This is done either in -&gt;kill_hook() of internal item or in
   kill_root() function when tree root is removed.
   ...
&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;and, it was &lt;em&gt;me&lt;/em&gt; rather than Hans who wrote this. It was long, long time ago, but I believe SCM logs are still here to prove this.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-5448246024063252445?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/5448246024063252445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=5448246024063252445' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5448246024063252445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5448246024063252445'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/06/and-now-to-subject-of-death.html' title='And now to the subject of death.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-6358462845663808948</id><published>2006-10-30T19:00:00.000Z</published><updated>2006-10-30T19:09:44.954Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>File system replacement algorithms (cont.)</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;a href="http://nikitadanilov.blogspot.com/2006/10/file-system-replacement-algorithms.html"&gt;Previous item&lt;/a&gt;.

&lt;h3&gt;3. User level tools.&lt;/h3&gt;
&lt;p&gt;
Replacement algorithms simulator is in &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/replacement.c"&gt;replacement.c&lt;/a&gt;&lt;/tt&gt;. It consists of conventional main loop that reads preprocessed trace records and feeds them to selected replacement algorithm. Replacement algorithms (&lt;tt&gt;struct repalg&lt;/tt&gt;) are executed in the following standard environment:
&lt;ul&gt;
&lt;li&gt;Primary storage (memory) which is an array (&lt;tt&gt;mm.m_frames[]&lt;/tt&gt;) of a given (through command line option) number of equal sized &lt;em&gt;frames&lt;/em&gt; (&lt;tt&gt;struct frame&lt;/tt&gt;). Some frames are &lt;em&gt;occupied&lt;/em&gt; by pages, others are free. Replacement algorithm may maintain some private information for each frame.&lt;/li&gt;
&lt;li&gt;Secondary storage which is an array &lt;tt&gt;mm.m_vpages[]&lt;/tt&gt; of a given number of pages (&lt;tt&gt;struct vpage&lt;/tt&gt;). This can be thought as a set of all distinct pages ever accessed by a trace being processed. Each page, in addition to its index in this array, is uniquely identified by a file and logical offset within this file. At any given moment in time page is either &lt;em&gt;resident&lt;/em&gt; (i.e., loaded into some frame in memory) or non-resident. Replacement algorithm may maintain some private information for each page.&lt;/li&gt;
&lt;li&gt;Array (&lt;tt&gt;mm.m_objects[]&lt;/tt&gt;) of files (&lt;tt&gt;struct object&lt;/tt&gt;). Each file maintains a list of all its pages (not frames!). This is needed for efficient emulation of truncate, see below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
These data structures simplify implementation of replacement algorithms, but do not directly match information available in the trace. This gap is filled by preprocessing script &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.awk"&gt;fslog.awk&lt;/a&gt;&lt;/tt&gt; that reads in whole trace and generates unique numeric identifiers for pages and files (these identifiers are used as array indices by replacement emulator). Script also does some additional book-keeping, collects few statistical counters, and does rudimentary sanity checking of the trace. Key point is to reliably tell when pages belong to the same or to the different files. Obvious solution of using &lt;tt&gt;(dev, ino)&lt;/tt&gt; pair as a unique file identifier doesn't work, because certain popular file systems tend to reuse inode numbers immediately after file deletion, leading to false positives. This is why trace record contains additional &lt;tt&gt;-&gt;fr_gen&lt;/tt&gt; and &lt;tt&gt;-&gt;fr_name&lt;/tt&gt; fields: tuple &lt;tt&gt;(dev, ino, generation, name)&lt;/tt&gt; is reliable file identity.
&lt;/p&gt;&lt;p&gt;
Another complication arises with truncate handling. In all other cases trace records produced by kernel map one to one into page accesses, handled by replacement algorithm. But in the case of truncate, kernel walks a list of &lt;em&gt;resident&lt;/em&gt; pages only. Producing trace records for each walked page isn't what we want, because this list depends on a replacement policy implemented by kernel. Instead, tracing patch generates only one record for whole truncate operation, with &lt;tt&gt;-&gt;fr_index&lt;/tt&gt; field indicating the first page to be truncated. For such record &lt;tt&gt;replacement.c&lt;/tt&gt; walks a list of all pages, associated with corresponding file and calls page based truncate entry point (&lt;tt&gt;repalg.m_punch()&lt;/tt&gt;) of replacement algorithm. It is to implement this walking efficiently that files exist as a first class entities in &lt;tt&gt;replacement.c&lt;/tt&gt;.
&lt;/p&gt;&lt;p&gt;
The only remaining bit is converting binary trace records into form suitable for &lt;tt&gt;fslog.awk&lt;/tt&gt;. This is done by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.c"&gt;fslog.c&lt;/a&gt;&lt;/tt&gt; based on &lt;tt&gt;exported-global.c&lt;/tt&gt; sample program from relayfs package.
&lt;/p&gt;
&lt;h3&gt;4. Results.&lt;/h3&gt;
&lt;h4&gt;4.0. Experiment description.&lt;/h4&gt;
&lt;p&gt;
Analyzed trace was obtained by running
&lt;pre&gt;
$ make defconfig &amp;&amp; make -j4 bzImage modules
&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
on a single processor machine (other machine characteristics such as memory size and available secondary storage do not matter, as was explained above) in 2.6.18-rc2 kernel source directory. In addition trace contains records generated during system boot-up. To avoid cluttering the trace with records generated by &lt;tt&gt;fslog.c&lt;/tt&gt; writes, its output was transferred to other machine by netcat(1). Total amount of output was 2.7GB (not provided due to size).
&lt;/p&gt;&lt;p&gt;
&lt;tt&gt;fslog.awk&lt;/tt&gt; &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.stat"&gt;processed&lt;/a&gt; 25927993 records, accessing total of 2356222 pages in 86839 distinct files. Resulting trace, suitable as input to &lt;tt&gt;replacement.c&lt;/tt&gt; is &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.trace.gz"&gt;here&lt;/a&gt; (79MB), file identities are &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.file"&gt;here&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
Following replacement algorithms were tested:
&lt;ul&gt;
&lt;li&gt;RANDOM
&lt;/li&gt;&lt;li&gt;LRU (least recently used)
&lt;/li&gt;&lt;li&gt;FIFO (first in, first out)
&lt;/li&gt;&lt;li&gt;FIFO2 (fifo, second chance)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://portal.acm.org/ft_gateway.cfm?id=805473&amp;type=pdf&amp;coll=portal&amp;dl=ACM&amp;CFID=15151515&amp;CFTOKEN=6184618"&gt;SFIFO&lt;/a&gt; (segmented fifo, by Rollins Turner and Henry Levy)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.vldb.org/conf/1994/P439.PDF"&gt;2Q&lt;/a&gt; (by Theodore Johnson and Dennis Shasha)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://citeseer.ist.psu.edu/bansal04car.html"&gt;CAR&lt;/a&gt; (by Sorav Bansal and Dharmendra S. Modha)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://citeseer.ist.psu.edu/megiddo03arc.html"&gt;ARC&lt;/a&gt; (by Nimrod Megiddo, Dharmendra Modha)
&lt;/li&gt;&lt;li&gt;LINUX (emulation of &lt;tt&gt;mm/vmscan.c&lt;/tt&gt;)
&lt;/li&gt;&lt;li&gt;WORST (theoretically worst possible replacement)
&lt;/li&gt;&lt;li&gt;OPT (theoretically optimal clairvoyant algorithm by Belady)&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
RANDOM, FIFO, FIFO2, LRU and Segmented FIFO are &amp;#8222;classical&amp;#8220; replacement algorithms invented and extensively studied in 60s. 2Q, CAR and ARC are &amp;#8222;new&amp;#8220; algorithms developed recently as interest to replacement policies reappeared. OPT and WORST algorithms cannot be implemented in practice, because they are both &amp;#8222;clairvoyant&amp;#8220; &amp;mdash; they look ahead through the trace. LINUX algorithm tries to emulate &lt;tt&gt;mm/vmscan.c&lt;/tt&gt; with the following limitations and simplifications:
&lt;ul&gt;
&lt;li&gt;no mapped or anonymous pages;
&lt;/li&gt;&lt;li&gt;no kswapd, only direct reclaim;
&lt;/li&gt;&lt;li&gt;all allocations are with GFP_FS;
&lt;/li&gt;&lt;li&gt;no non-fs caches;
&lt;/li&gt;&lt;li&gt;no low_page reserves;
&lt;/li&gt;&lt;li&gt;single zone.&lt;/li&gt;
&lt;/ul&gt;
which is reasonable for comparison of file system dominated non-degenerate work-loads.
&lt;/p&gt;&lt;p&gt;
2Q and SFIFO have tunable parameters (see their papers referenced above for description of parameters). 2Q was tested with &lt;i&gt;kin&lt;/i&gt; of 25, and &lt;i&gt;kout&lt;/i&gt; ranging from 10 to 50 with step 10. &lt;i&gt;kout&lt;/i&gt; of 10 proved to produce best results, and this value was used in comparison with other algorithms. SFIFO was tested &amp;#8222;tail lru percentage&amp;#8220; from 0 (pure FIFO) to 20, with very small observed effect on results. All other algorithms are self-tuning.
&lt;/p&gt;&lt;p&gt;
All algorithms were ran against the same trace, and tested with the same set of memory sizes (varying from 5 to 4M frames, which corresponds to 20KB&amp;mdash;16GB range of memory sizes with 4K frame).
&lt;/p&gt;&lt;p&gt;
Results, together with shell commands used to produce them are available &lt;a href="http://linuxhacker.ru/~nikita/fslog/results"&gt;here&lt;/a&gt;. A couple of notes:
&lt;ul&gt;
&lt;li&gt;OPT algorithm is extremely slow (as expected);
&lt;/li&gt;&lt;li&gt;LINUX algorithm fails for very small memories (less than 64 frames).&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;h4&gt;4.1. Graphs: overall.&lt;/h4&gt;
&lt;p&gt;
Below are few graphs, created by gnuplot &lt;a href="http://linuxhacker.ru/~nikita/fslog/plot.gnuplot"&gt;script&lt;/a&gt; (input files for gnuplot are generated by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/process.hits"&gt;process.hits&lt;/a&gt;&lt;/tt&gt;, and PNG images are generated from postscript by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/generate-png"&gt;generate-png&lt;/a&gt;&lt;/tt&gt;). Everywhere X-axis (horizontal) is memory size (logarithmical), and Y-axis (vertical) is hit ratio in percents, unless specified otherwise.
&lt;/p&gt;&lt;p&gt;
&lt;a name="4.1.overall"&gt;&lt;/a&gt;First, all algorithms on the single graph:
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all.png" border=0&gt;
&lt;/center&gt;
&lt;/p&gt;&lt;p&gt;
One immediate observation is that for memories larger than 28MB difference between algorithms is very small. Another notable thing is that in 56KB&amp;mdash;6MB range LINUX algorithms is worse than everything except WORST. Remarkably it's even worse than RANDOM, which surely is quite a feat of engineering.
&lt;/p&gt;&lt;p&gt;
Next graph shows how algorithms improve upon WORST. Here Y-axis is difference between hit ratio of algorithm and WORST for corresponding memory size.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
As it is by definition impossible to not beat WORST, improvement (or lack thereof) against RANDOM is also useful measure:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-random.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Next graph shows how far algorithms fall behind OPT. In this graph Y-axis is given by &lt;tt&gt;100.0 - hit_ratio(OPT) + hit_ratio(ALG)&lt;/tt&gt;, that is, OPT corresponds to 100.0.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Revealed behavior is quite interesting. For very small memory sizes, all algorithms perform more or less equally bad, but as memory size increases, OPT quickly outperforms everything else. This corresponds to the initial dip in the 32KB&amp;mdash;512KB range. After that point, non-OPT algorithms really start &amp;#8222;working&amp;#8220; and gradually approach OPT, reaching (in concert!) local optimum somewhere in 32MB&amp;mdash;64MB range. But as memory size increases even more, &lt;em&gt;all&lt;/em&gt; of them start lagging behind OPT more and more again. In 512MB&amp;mdash;16GB range all algorithms converge, because in this here where total working set of the work load in question lies, and once work set fits into memory it is hard to behave too bad.
&lt;/p&gt;&lt;p&gt;
Second local minimum is rather strange. As it happens for all non-OPT algorithms in a regular manner, it's logical to assume that it is result of some property of the work-load in question. One might hypothesize, that in this range of memory sizes, OPT algorithm is able to exploit some long-term patterns in file system accesses during kernel build.
&lt;/p&gt;&lt;p&gt;
&lt;h4&gt;4.2. Graphs: tunable parameters.&lt;/h4&gt;
&lt;p&gt;
Next, let's look how tunable parameters affect 2Q and SFIFO performance:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/2q-var-lru-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Labels are in &lt;tt&gt;2Q:kin:kout&lt;/tt&gt; format. Obviously, the smaller &lt;i&gt;kout&lt;/i&gt; the better, and 2Q indeed beats LRU most of the time, in accordance with claims of its authors.
&lt;/p&gt;&lt;p&gt;
The same for SFIFO.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/sfifo-var-lru.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Segmented FIFO keeps frames in two lists: head and tail. Head list (containing &amp;#8222;hot&amp;#8220; pages) is maintained in FIFO discipline, and tail list &amp;mdash; in LRU discipline. Size of the tail list is set to fixed percentage of full memory (when this percentage is 0, SFIFO degenerates into FIFO. When it is 100.0, SFIFO becomes LRU.). The logic behind this is that by making tail LRU list sufficiently small it becomes practically feasible to implement LRU in it by un-mapping pages on entry to tail list. Our results show that for all reasonable sizes of tail list, difference in hit ratio is negligible.
&lt;/p&gt;
&lt;h4&gt;4.2. Graphs: classical algorithms.&lt;/h4&gt;
&lt;p&gt;
Let's look at some data of historical interest: how &amp;#8222;classical&amp;#8220; replacement algorithms (LRU, FIFO, and FIFO2) behave relative to OPT, WORST, and RANDOM (LINUX is shown here too, because it basically falls into the same class of algorithms).
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Classical algorithms versus WORST:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-vs-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
And versus OPT:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-vs-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
It's interesting to look how these algorithms behave in the memory ranges typical for the time when they were actively researched:
&lt;/p&gt;&lt;p&gt;
2MB&amp;mdash;32MB range:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-2M-32M.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
At some points difference in hit ratios can reach 5%, but as we move to larger memories (16MB&amp;mdash;4GB)...
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-16M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
difference shrinks to ~1% range and remains there (256MB&amp;mdash;4GB):
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-256M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;h4&gt;4.3. Graphs: LINUX.&lt;/h4&gt;
&lt;p&gt;
At last, compare how LINUX fares relative to other algorithms. We shall concentrate on data for large memories (64MB&amp;mdash;4GB range), because behavior of LINUX algorithm in low memory setups is clearly visible at the &lt;a href="#4.1.overall"&gt;overall graph&lt;/a&gt;: it loses to everyone.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/lru-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/fifo-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/fifo2-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/arc-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/2q-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
The natural question arises: why LINUX algorithm is so... not brilliant (albeit, keep in mind that all this happens only few percent within OPT, so not too much is at the stake)? As was noted at the beginning, unified FS/VM caching forces replacement algorithm to use only bare minimum of available per-page information. In particular, it so happens that for clean file system pages, LINUX is equivalent to FIFO (known bad algorithm), and for dirty pages &amp;mdash; to FIFO2.
&lt;/p&gt;
&lt;!--
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/modern-lru-opt-16M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/modern-lru-opt.png" border=0&gt;
&lt;/center&gt;
--&gt;
&lt;h3&gt;5. Conclusion.&lt;/h3&gt;
&lt;p&gt;
Assorted miscellaneous notes, actually.
&lt;/p&gt;&lt;p&gt;
One thing obvious from traces, but not mentioned above is that larger portion of all trace records is for page faults. Absolute majority of them are compulsory misses that happen because every new process maps all standard libraries into its address space. By looking at the traces, it seems that optimizations in this area (e.g., pre-mapping all already resident pages of the given library) would be clearly advantageous.
&lt;/p&gt;&lt;p&gt;
Handling of file system pages by LINUX algorithms can definitely be improved.
&lt;/p&gt;
&lt;h3&gt;6. Future directions.&lt;/h3&gt;
&lt;p&gt;
More algorithms are to be implemented in &lt;tt&gt;replacement.c&lt;/tt&gt;: LFU, LRU/k, LIRS, etc. Also, more statistics (working set size, page fault rate, etc.) can be collected.
&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-6358462845663808948?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/6358462845663808948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=6358462845663808948' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/6358462845663808948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/6358462845663808948'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/10/previous-item.html' title='File system replacement algorithms (cont.)'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1326414144463107737</id><published>2006-10-29T22:08:00.000Z</published><updated>2006-10-30T19:13:04.437Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>File system replacement algorithms.</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;h3&gt;1. Introduction.&lt;/h3&gt;This article describes results of a bit of research I made on efficiency of file system cache replacement algorithms. As everybody knows file system tries to keep some portions of its backing secondary storage (disk) cached in the primary storage (memory). In particular portion of file system data or meta-data that is being accessed right now has to be present in the memory, because kernel cannot directly manipulate data on the disk. &lt;em&gt;Replacement problem&lt;/em&gt; occurs when this cache grows too large (which it tends to do sooner or later, as secondary storage is usually much larger than memory). When cache cannot grow anymore, and new data have to be accessed, something has to be thrown out of the cache. The selection of cache item to be removed is made by &lt;em&gt;replacement algorithm&lt;/em&gt;. Choice of this algorithm affects file system performance, because if/when item removed from cache is re-accessed, file system has to wait for disk IO to read it again. Replacement algorithms try to minimize this overhead, by using various statistical information and trying to predict future accesses.

The very possibility of such predictions is based on assumed regularities in file system accesses, most notable being &lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality of reference&lt;/a&gt;&lt;/em&gt; and access patterns, such as sequential file scanning.

Research in replacement algorithms is as old as file systems, but few last decades in was mainly done in the context of data base engines (that also cache part of database in the memory). The reason for this is that in most modern operating system kernels file system caching was unified with VM caching. Perceived advantages of this unification are:
&lt;ul&gt;&lt;li&gt;simplification,
&lt;/li&gt;&lt;li&gt;support of &lt;a href="http://opengroup.org/onlinepubs/009695399/functions/mmap.html"&gt;mmap(2)&lt;/a&gt; style accesses to file system, and
&lt;/li&gt;&lt;li&gt;sharing of memory between file system and VM, without imposing artificial limits on size of each cache.
&lt;/li&gt;&lt;/ul&gt;The latter goal was never fully achieved: all existing implementations treat file system and VM pages differently to some extent, because system performance is miserable otherwise. This hints that access patterns are so different for file system and VM pages, that unified caching is not necessary the best solution.

Another problem with unified caching is that the same replacement algorithm has to be used, and this basically means that replacement algorithm may rely only on information available for both file system and VM pages to make its decisions. As a set of attributes that file system can maintain for its pages is a strict superset of attributes maintained for VM pages, unified replacement algorithm degenerates into a &lt;a href="http://en.wikipedia.org/wiki/Page_replacement_algorithms"&gt;VM replacement algorithm&lt;/a&gt; and all additional hints that file system can provide are thrown away.

Experiments described below are an attempt to determine whether separate replacement algorithm can improve file system performance.

To measure efficiency of replacement algorithms file system traces were collected, and then processed by a user-level simulator.

Trace is a sequence of records each describing a particular access to some page of a file (see details below). User level simulator processes trace record by record, emulating both memory and secondary storage, keeping track of currently cached pages, and performing replacement decisions when necessary (also, see below for details).
&lt;h3&gt;2. Tracing method.
&lt;/h3&gt;An important point in collecting file system traces is to make them independent from caching and replacement algorithms implemented in the kernel being traced. This, for example, rules out placing tracepoints at the level of &lt;tt&gt;struct address_space_operations&lt;/tt&gt; (or below), because code at that level is invoked by VM, and as a result sequence of event depends on algorithms used by VM.

On the other hand, placing tracepoints at the syscall/VFS level is not very convenient either, because, while usable for tracing access to data pages (read/write/truncate), it is not adequate for tracing meta-data.

The only remaining possibility is to put tracepoints into file system driver, but that would require changing all file systems. As a compromise, tracepoints were placed in &lt;tt&gt;mm/filemap.c&lt;/tt&gt;, &lt;tt&gt;mm/readahead.c&lt;/tt&gt; and &lt;tt&gt;mm/truncate.c&lt;/tt&gt; "generic" code that is used by many file systems:
&lt;dl&gt;&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=do_generic_mapping_read"&gt;do_generic_mapping_read()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts reads&lt;/dd&gt;&lt;dt&gt;
&lt;/dt&gt;&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=filemap_nopage"&gt;filemap_nopage&lt;/a&gt;()&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts page faults on file system pages&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=filemap_nopage"&gt;__grab_cache_page()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts writes&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=truncate_inode_pages_range"&gt;truncate_inode_pages_range()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts truncates&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=__do_page_cache_readahead"&gt;__do_page_cache_readahead()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts readahead
&lt;/dd&gt;&lt;/dl&gt;All tracepoints look exactly the same:
&lt;div class="code-title"&gt;tracepoint&lt;/div&gt;
&lt;div class="code"&gt;&lt;pre&gt;
 fslog(mapping, index, page, opcode);
&lt;/pre&gt;&lt;/div&gt;

Where &lt;tt&gt;mapping&lt;/tt&gt; is an object (inode) on which operation is preformed, &lt;tt&gt;index&lt;/tt&gt; is a logical offset of accessed page within object, &lt;tt&gt;page&lt;/tt&gt; is a page itself, if present, NULL otherwise, and &lt;tt&gt;opcode&lt;/tt&gt; is operation code, one of

&lt;div class="code-title"&gt;enum fslog_rec_type&lt;/div&gt;
&lt;div class="code"&gt;&lt;pre&gt;
enum fslog_rec_type {
        FSLOG_READ,    /* read */
        FSLOG_RA,      /* read-ahead */
        FSLOG_WRITE,   /* write */
        FSLOG_PFAULT,  /* page-fault */
        FSLOG_PUNCH    /* page truncate */
};
&lt;/pre&gt;&lt;/div&gt;&lt;tt&gt;fslog()&lt;/tt&gt; packs arguments into standard event record:
&lt;div class="code-title"&gt;struct fslog_record
&lt;/div&gt;&lt;div class="code"&gt;&lt;pre&gt;struct fslog_record {
        __u32 fr_no;       /* monotonically increasing event counter.
                              Used to detect lost events. */
        __u32 fr_time;     /* event time in microseconds. */

        __u32 fr_dev;      /* major:minor of device, where file is located. */
        __u32 fr_ino;      /* file inode number */

        __u32 fr_gen;      /* file inode generation. */
        __u32 fr_index;    /* logical index of accessed page. */

        __u16 fr_pid;      /* pid of process. */
        __u8  fr_type;     /* access type, taken from enum fslog_rec_type. */
        __u8  fr_bits;     /* miscellaneous page bits. */
        __u32 fr_pad;      /* alignment padding. */

        char  fr_comm[16]; /* "process name". */
        char  fr_name[16]; /* "file name". */
};
&lt;/pre&gt;&lt;/div&gt;That might looks like awfully excessive amount of information, but it's necessary to reliably identify unique pages and files, as will be shown below.

Once record is composed, it is exported to the user space through &lt;a href="http://relayfs.sourceforge.net/"&gt;relayfs&lt;/a&gt;.

Tracing patch for 2.6.18-rc2 kernel is available &lt;a href="http://linuxhacker.ru/%7Enikita/fslog/fslog.patch"&gt;here&lt;/a&gt;.

&lt;a href="http://nikitadanilov.blogspot.com/2006/10/previous-item.html"&gt;Continued&lt;/a&gt;.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1326414144463107737?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1326414144463107737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1326414144463107737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1326414144463107737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1326414144463107737'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/10/file-system-replacement-algorithms.html' title='File system replacement algorithms.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-115359710401539766</id><published>2006-07-22T19:33:00.000Z</published><updated>2006-07-22T19:38:24.026Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>A voice of the reason from the distant past</title><content type='html'>Dedicated to VM and file system developers and researches...
&lt;blockquote&gt;
It is immediately apparent from these figures that moving-arm disks should never be used, neither for paging applications nor for any other heavy-traffic auxiliary memory applications.
&lt;/blockquote&gt;&lt;div style="text-align: right;"&gt;Peter J. Denning -- &lt;a href="http://portal.acm.org/ft_gateway.cfm?id=356573&amp;type=pdf&amp;coll=portal&amp;dl=ACM&amp;CFID=15151515&amp;CFTOKEN=6184618"&gt;Virtual Memory&lt;/a&gt;.
&lt;/div&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/VM" rel="tag"&gt;VM&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-115359710401539766?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/115359710401539766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=115359710401539766' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/115359710401539766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/115359710401539766'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/07/voice-of-reason-from-distant-past.html' title='A voice of the reason from the distant past'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114340358190033239</id><published>2006-03-26T20:01:00.000Z</published><updated>2006-03-26T20:31:55.380Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='reiser4'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>reiser4: 1. internal tree</title><content type='html'>&lt;h1&gt;reiser4: 1. internal tree&lt;/h1&gt;

&lt;p&gt;
     This continues previous entry: &lt;a href="http://nikitadanilov.blogspot.com/2005/12/reiser4-0-introduction.html"&gt;introduction&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
   &lt;ul&gt;
     &lt;li&gt;0. &lt;a href="#internal-tree-0"&gt;B-trees overview&lt;/a&gt;
     &lt;/li&gt;&lt;li&gt;1. &lt;a href="#internal-tree-1"&gt;lookup and modification&lt;/a&gt;
     &lt;/li&gt;&lt;li&gt;2. &lt;a href="#internal-tree-2"&gt;lookup optimizations&lt;/a&gt;
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/p&gt;
&lt;h4&gt;0. B-trees overview&lt;/h4&gt;
&lt;div class="kernel"&gt;&lt;a name="internal-tree-0"&gt;&lt;/a&gt;
&lt;p&gt;
    &lt;a href="http://en.wikipedia.org/wiki/B-tree"&gt;B-tree&lt;/a&gt; is am umbrella term for a variety of similar algorithms used to implement &lt;a href="http://en.wikipedia.org/wiki/Associative_array"&gt;dictionary&lt;/a&gt; abstraction suitable in a form suitable for external storage. Reiser4 version of this algorithms, officially known as a &lt;a href="http://en.wikipedia.org/wiki/Dancing_tree"&gt;dancing tree&lt;/a&gt; is closest to the &lt;a href="http://en.wikipedia.org/wiki/B%2B_tree"&gt;B&lt;sup&gt;+&lt;/sup&gt;-tree&lt;/a&gt;. Basically, in B&lt;sup&gt;+&lt;/sup&gt;-tree user-supplied data records are stored in &lt;em&gt;leaf nodes&lt;/em&gt;. Each leaf node keeps records from some particular key range (adjusted dynamically). Each leaf node is referenced from its &lt;em&gt;parent&lt;/em&gt;: this reference is a pointer to the child (block number usually) and the smallest key in the key range covered by this leaf. Parent node contains multiple references to its children nodes, again from some particular key range. Parent node may have its own parent and so on until whole key space is covered.
&lt;/p&gt;&lt;p&gt;
   Compare this with B-trees proper, where data records are stored at the levels other than leaf one. Also compare this with &lt;a href="http://en.wikipedia.org/wiki/PATRICIA"&gt;radix tree&lt;/a&gt; (aka &lt;em&gt;PATRICIA&lt;/em&gt;) where key range covered by given node is uniquely determined by its level rather than adjusted dynamically as in B-trees.
&lt;/p&gt;&lt;p&gt;
  Contents of reiser4 internal tree are initially stored on the disk. As file system operations go on, some blocks from the tree are read into memory and cached there. When new node is added to the tree, it first exists as a block-size buffer in memory. Under some conditions portions of tree are written out from memory back to the stable storage. During write-out, nodes that were marked &lt;em&gt;dirty&lt;/em&gt; (either as a result of a modification, or because they are newly created), are written to the appropriate disk block and marked &lt;em&gt;clean&lt;/em&gt;. Clean nodes can be discarded from memory.
&lt;/p&gt;
&lt;/div&gt;


&lt;h4&gt;1. lookup and modification&lt;/h4&gt;
&lt;div class="kernel"&gt;&lt;a name="internal-tree-1"&gt;&lt;/a&gt;
&lt;p&gt;
   Lookup operation locates a record with a given key in a tree, or locates a place where such record will be inserted (this place is uniquely identified by a key) if it doesn't exist yet. All other tree operations start with lookup, because they have to find a place in a tree identified by given key.
&lt;/p&gt;&lt;p&gt;
   Roughly speaking, lookup starts from the top of the tree, searches through index node to find it which of its children given key falls, loads that child node and repeats until it gets to the leaf level. One can say that lookup is top-to-bottom tree operation.
&lt;/p&gt;
   This poses two questions:
&lt;ul&gt;
  &lt;li&gt;What is the top of a tree and how to find it?&lt;/li&gt;
  &lt;li&gt;How to find out which child node to proceed with?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  First question seems trivial, because every tree has a root node, right? The problem is that, as will be explained below, concurrent tree modification operation may grow the tree by adding new root to it (so that old root becomes child of a new one), or shrink it by killing existing root. To avoid this, reiser4 tree has special imaginary node, existing only in memory that logically hangs just above root node. First of all, lookup locks this node and learns location of root node from it. After this, it loads root node in memory and releases the lock. This imaginary node is called &lt;a href="http://en.wiktionary.org/wiki/%C3%BCber"&gt;uber&lt;/a&gt;-node. Curiously enough, Sun ZFS uses exactly the same term for the very similar thing. They even have &lt;tt&gt;0x00babl0c&lt;/tt&gt; magic number in their disk format, that is supposed to be as close as possible to the &lt;em&gt;pronunciation&lt;/em&gt; of "uber block" (even more funny, "bablo" is Russian slang word for money, bucks).
&lt;/p&gt;&lt;p&gt;
  To make search for a child node containing given key efficient, keys in the parent node are stored in an ordered array, so that binary search can be used. That binary search is (under many workloads) the single most critical CPU operation.
&lt;/p&gt;
    Now we known enough to code reiser4 lookup algorithm:
&lt;div class="code-title"&gt;reiser4/search.c:traverse_tree()&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
traverse_tree(key) {
        node     *parent; /* parent node */
        node     *child;  /* child node */
        position  ptr;    /* position of record within node */

        child = ubernode;
        ptr   = ubernode.root; /* put root block number in ptr */

        while (!node_is_leaf(child)) {
                parent = child;
                /* load node, stored at the given block, into memory */
                child = node_at(ptr);
                lock(child);
                ptr = binary_search(child, key);
                unlock(parent);
        }
        return ptr;
}
&lt;/pre&gt;
&lt;/div&gt;
Few comments:
&lt;ul&gt;
&lt;li&gt;&lt;tt&gt;position&lt;/tt&gt; identifies a record within node. For leaf level this is actual record with user data, for non-leaf levels, record contains pointers to the child node.
&lt;/li&gt;&lt;li&gt;note that lock on the child node is acquired before lock on the parent is released, that is, two locks are held at some moment. This is traditional tree traversal technique called &lt;em&gt;lock coupling&lt;/em&gt; or &lt;em&gt;lock crabbing&lt;/em&gt;.
&lt;/li&gt;&lt;li&gt;&lt;tt&gt;traverse_tree()&lt;/tt&gt; returns with ptr positioned at the record with required key (or at the place where such record would be inserted) and with appropriate leaf node locked.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   As was already mentioned above, tree lookup is comparatively expensive (computationally, if nothing more) operation. At the same time, almost everything in reiser4 uses it extensively. As a result, significant effort has been put into making tree lookup more efficient. Algorithm itself doesn't leave much to be desired: its core is binary search and it can be optimized only that far. Instead, multiple mechanisms were developed that allows to bypass full tree lookup under some conditions. These mechanisms are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#internal-tree-1-1"&gt;seals&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="#internal-tree-1-2"&gt;vroot&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="#internal-tree-1-3"&gt;look-aside cache&lt;/a&gt; (cbk cache)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1.1. seals&lt;/h5&gt;&lt;a name="internal-tree-1-1"&gt;&lt;/a&gt;
&lt;p&gt;
   A seal is a weak pointer to a record in the tree. Every node in a tree maintains &lt;em&gt;version counter&lt;/em&gt;, that is incremented on each node modification. After lookup for a given key was performed, seal can be created that remembers block number of found leaf node and its version counter at the moment of lookup. Seal verification process checks that node recorded in the seal is still in the tree and that its version counter is still the same as recorded. If both conditions are met, pointer to the record returned by lookup can still be used, and additional lookup for the same key can be avoided.
&lt;/p&gt;
&lt;h5&gt;1.2. vroot&lt;/h5&gt;&lt;a name="internal-tree-1-2"&gt;&lt;/a&gt;
&lt;p&gt;
   Higher-level file system object such as regular files and directories is represented as a set of tree records. Keys of these records are usually confined in some key range, and, due to the nature of B-trees, are all stored in the nodes having common ancestor node that is not necessary root. That is, records constituting given object are located in some subtree of reiser4 internal tree. Idea of vroot (&lt;em&gt;virtual root&lt;/em&gt;) optimization is to track root of that sub-tree and to start lookups for object records from vroot rather than from real tree root. vroot is updated lazily: when lookup finds that tree was modified so that object subtree is no longer rooted at vroot, tree traversal restarts from real tree root and vroot is determined during descent.
&lt;/p&gt;&lt;p&gt;
   Additional important advantage of vroot is that is decreases lock contention for the root node.
&lt;/p&gt;
&lt;h5&gt;1.3. look-aside cache&lt;/h5&gt;&lt;a name="internal-tree-1-3"&gt;&lt;/a&gt;
&lt;p&gt;
  Look-aside cache is simply a list of last N leaf nodes returned by tree lookup. This list is consulted before embarking into full-blown top-to-bottom traversal. This simple mechanism works due to &lt;a href="http://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality of reference&lt;/a&gt; for tree accesses.
&lt;/p&gt;
  To be continued:
&lt;ul&gt;
     &lt;/li&gt;&lt;li&gt;2. concurrency control: lock ordering, hi-lo ordering
     &lt;/li&gt;&lt;li&gt;3. eottl
     &lt;/li&gt;&lt;li&gt;4. node format
&lt;/ul&gt;
&lt;/div&gt;


&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/reiser4" rel="tag"&gt;reiser4&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114340358190033239?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114340358190033239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114340358190033239' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114340358190033239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114340358190033239'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/reiser4-1-internal-tree.html' title='reiser4: 1. internal tree'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114301477508079978</id><published>2006-03-22T07:59:00.000Z</published><updated>2006-03-22T08:06:35.003Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Jon Beck dies</title><content type='html'>&lt;div class="mourning"&gt;
&lt;center&gt;
Jon Beck, author of &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Beck%27s_monadicity_theorem"&gt;Beck's condition&lt;/a&gt;&lt;/i&gt;, died suddenly on March 11.
&lt;/center&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Mathematics" rel="tag"&gt;Mathematics&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114301477508079978?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114301477508079978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114301477508079978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114301477508079978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114301477508079978'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/jon-beck-dies.html' title='Jon Beck dies'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114141075488944431</id><published>2006-03-03T18:31:00.000Z</published><updated>2006-03-04T15:36:01.300Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Why windows will collapse ultimately</title><content type='html'>&lt;pre&gt;Subject: [ntdev] WdfUsbTargetDeviceSendControlTransferSynchronously and timeouts&lt;/pre&gt;

&lt;b&gt;update&lt;/b&gt;: Like this wasn't enough.

Below are excerpts from
&lt;pre&gt;
find . -name \*dll |        xargs strings -- |        grep -i '^[a-z0-9_]*$' |        awk '{ print length($1) "\t" $1 }' |        sort -n
&lt;/pre&gt;
output (executed in WinXP system directory):
&lt;pre&gt;
50      ZwAccessCheckByTypeResultListAndAuditAlarmByHandle
51      Java_NPDS_npDSJavaPeer_SetSendMouseClickEvents_stub
51      Java_NPDS_npDSJavaPeer_SetShowPositionControls_stub
51      JET_errDistributedTransactionNotYetPreparedToCommit
52      ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
52      ConvertSecurityDescriptorToStringSecurityDescriptorA
52      ConvertSecurityDescriptorToStringSecurityDescriptorW
53      ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE
55      ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
55      SxspComProgIdRedirectionStringSectionGenerationCallback
56      Java_NPDS_npDSJavaPeer_GetSendOpenStateChangeEvents_stub
56      Java_NPDS_npDSJavaPeer_GetSendPlayStateChangeEvents_stub
56      SxspComTypeLibRedirectionStringSectionGenerationCallback
57      SxspComputeInternalAssemblyIdentityAttributeBytesRequired
57      SxspWindowClassRedirectionStringSectionGenerationCallback
62      SxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize
62      SxspGenerateTextuallyEncodedPolicyIdentityFromAssemblyIdentity
64      RtlpQueryAssemblyInformationActivationContextDetailedInformation
71      &lt;a href="http://www.openrce.org/reference_library/win32_call_chains/XPSP2/NTDLL/RtlpQueryFilesInAssemblyInformationActivationContextDetailedInformation"&gt;RtlpQueryFilesInAssemblyInformationActivationContextDetailedInformation&lt;/a&gt;
&lt;/pre&gt;

which probably gives us the champion. 

As a comparison, for linux-2.6.15
&lt;pre&gt;
find . -type f -follow -name '*.[chS]' |        xargs grep -hi '[a-z0-9_]\{70,\}' -- /dev/null
&lt;/pre&gt;
gives:
&lt;pre&gt;
70 ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060
&lt;/pre&gt;
So windows is one character closer to hell than linux.
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Windows" rel="tag"&gt;Windows&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114141075488944431?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114141075488944431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114141075488944431' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114141075488944431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114141075488944431'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/why-windows-will-collapse-ultimately.html' title='Why windows will collapse ultimately'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113882577109399193</id><published>2006-02-01T20:02:00.000Z</published><updated>2006-02-01T20:34:44.473Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>ext3: magic, more magic.</title><content type='html'>&lt;span class="fullpostellipsis"&gt;
&lt;p&gt;
ext3 htree code in Linux kernel implements peculiar version of &lt;a href="http://www.bluerwhite.org/btree/"&gt;balanced tree&lt;/a&gt; used to efficiently handle large directories.
&lt;/p&gt;&lt;p&gt;
htree directory consists of block sized nodes. Some of them (leaf nodes) contain directory entries in the same format as ext2. Other nodes contain &lt;i&gt;index&lt;/i&gt;: they are filled with hashes and pointers to other nodes.
&lt;/p&gt;&lt;p&gt;
When new file is created in a directory, a directory entry is inserted in one of leaf nodes. When leaf node has not enough space for new entry, new node is appended to the tree, and part of directory entries is moved there. This process is known as a &lt;i&gt;split&lt;/i&gt;. Pointer to new node is then inserted into some index node, and new node can overflow at this point, causing another split and so on.
&lt;/p&gt;&lt;p&gt;
If splits occur whole way up to the root of the tree, new root has to be added (tree grows).
&lt;/p&gt;&lt;p&gt;
It's obvious that in the worst case (extremely rare in practice) insertion of a new entry may require a new block on each tree level, plus new root, right? Now, looking at the &lt;a href="http://lxr.linux.no/ident?i=ext3_dx_add_entry"&gt;&lt;tt&gt;ext3_dx_add_entry()&lt;/tt&gt;&lt;/a&gt; function we see something strange:
&lt;/p&gt;
&lt;div class="code-title"&gt;&lt;a href="http://lxr.linux.no/source/fs/ext3/namei.c#L1515"&gt;fs/ext3/namei.c:ext3_dx_add_entry()&lt;/a&gt;&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
                 } else {
                         dxtrace(printk("Creating second level index...\n"));
                         memcpy((char *) entries2, (char *) entries,
                                icount * sizeof(struct dx_entry));
                         dx_set_limit(entries2, dx_node_limit(dir));
 
                         /* Set up root */
                         dx_set_count(entries, 1);
                         dx_set_block(entries + 0, newblock);
                         ((struct dx_root *) frames[0].bh-&gt;b_data)-&gt;info.indirect_levels = 1;
 
                         /* Add new access path frame */
                         frame = frames + 1;
                         frame-&gt;at = at = at - entries + entries2;
                         frame-&gt;entries = entries = entries2;
                         frame-&gt;bh = bh2;
                         err = ext3_journal_get_write_access(handle,
                                                              frame-&gt;bh);
                         if (err)
                                 goto journal_error;
                 }
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
At this moment &lt;tt&gt;entries&lt;/tt&gt; points to the already existing full node and &lt;tt&gt;entries2&lt;/tt&gt; to the newly created one. As one can see, contents of &lt;tt&gt;entries&lt;/tt&gt; is shifted into &lt;tt&gt;entries2&lt;/tt&gt;, and &lt;tt&gt;entries&lt;/tt&gt; is declared to be new root of the tree. So now tree has a root node with a single pointer to the index node that... still has not enough free space (remember &lt;tt&gt;entries2&lt;/tt&gt; got everything &lt;tt&gt;entries&lt;/tt&gt; had). Omitted code that follows proceeds with splitting leaf node, assuming that its parent has enough space to insert a pointer to the new leaf. So how this is supposed to work? Or, does this work at all? That's tricky part and the curious reader is invited to try to infer what's going on without looking at the rest of this post.
&lt;/p&gt;
&lt;b&gt;[&lt;/b&gt;full text follows&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;
&lt;span class="fullpost"&gt;
&lt;p&gt;The answer is simple: by ext3 htree design, capacity of the root node is smaller than that of non-root index one. This is a byproduct of binary compatibility between htree and old ext2 format: root node is always the first block in the directory and it always contains dot and dotdot directory entries. As a result, when contents of old root is copied into new node, that node ends up having enough space for two additional entries.
&lt;/p&gt;&lt;p&gt;
This is obviously one of the worst hacks &lt;b&gt;and&lt;/b&gt; least documented at that. Shame.
&lt;/p&gt;&lt;p&gt;
Thanks to Alex Tomas for clearing this mystery for me. As he says: "&lt;i&gt;Htree code is simple to understand: it only takes to tune yourself to Daniel Phillips brain-waves frequency&lt;/i&gt;".
&lt;/p&gt;
&lt;/span&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113882577109399193?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113882577109399193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113882577109399193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113882577109399193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113882577109399193'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/02/ext3-magic-more-magic.html' title='ext3: magic, more magic.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113699963009595222</id><published>2006-01-11T16:38:00.000Z</published><updated>2006-01-11T17:14:25.563Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>A bit of out-of-context quoting</title><content type='html'>&lt;blockquote&gt;
&lt;a href="http://blogs.sun.com/roller/resources/esaxe/recruiting-preso-v2.pdf"&gt;Lessons Learned&lt;/a&gt;
&lt;ul&gt;
    &lt;li&gt; Solaris has been functioning, essentially, by accident, for over one year.&lt;br&gt;
         &lt;i&gt;We realize this again and again, every so often...&lt;/i&gt;&lt;/li&gt;
    &lt;li&gt;It is amazing that anything works at all&lt;/li&gt;
    &lt;li&gt;It's all broken&lt;/li&gt;
    &lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Solaris" rel="tag"&gt;Solaris&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113699963009595222?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113699963009595222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113699963009595222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113699963009595222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113699963009595222'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/01/bit-of-out-of-context-quoting.html' title='A bit of out-of-context quoting'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113698564744894743</id><published>2006-01-11T13:17:00.000Z</published><updated>2006-01-11T13:20:47.463Z</updated><title type='text'>A visit to the countryside.</title><content type='html'>&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0047.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0047.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- hidden church --&gt;
&lt;br&gt;
The Hidden Church
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0050.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0050.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- oka --&gt;
&lt;br&gt;
Oka riverside
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0055.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0055.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- a window --&gt;
&lt;br&gt;
An interior of a room of &lt;a href="http://en.wikipedia.org/wiki/Vasily_Polenov"&gt;Polenov's&lt;/a&gt; house.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0054.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0054.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- butterflies --&gt;
&lt;br&gt;
A painting by Polenov.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0044.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0044.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- ice tree --&gt;
&lt;br&gt;
An ice tree.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0058.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0058.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- landscape --&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0063.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0063.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- landscape with a bus --&gt;
&lt;br&gt;
Landscapes.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0018.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0018.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- wisent aurochs --&gt;
&lt;br&gt;
A wisent.
&lt;br&gt;&lt;br&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Russia" rel="tag"&gt;Russia&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Oka" rel="tag"&gt;Oka&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113698564744894743?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113698564744894743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113698564744894743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113698564744894743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113698564744894743'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/01/visit-to-countryside.html' title='A visit to the countryside.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113494322028231145</id><published>2005-12-18T21:58:00.000Z</published><updated>2005-12-18T22:43:43.293Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='reiser4'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>reiser4: 0. introduction</title><content type='html'>&lt;h1&gt;reiser4: 0. introduction&lt;/h1&gt;

This is an introduction to the series of entries I am going to write about
reiser4 file system. The plan, for the time being, goes like this:

&lt;ul&gt;
&lt;li&gt;0. introduction
   &lt;ul&gt;
     &lt;li&gt;0. trivia
     &lt;/li&gt;&lt;li&gt;1. reiser4 strong points
     &lt;/li&gt;&lt;li&gt;2. architecture overview
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;1. internal tree
   &lt;ul&gt;
     &lt;li&gt;0. B-trees overview
     &lt;/li&gt;&lt;li&gt;1. lookup and modification
     &lt;/li&gt;&lt;li&gt;2. concurrency control: lock ordering, hi-lo ordering
     &lt;/li&gt;&lt;li&gt;3. eottl
     &lt;/li&gt;&lt;li&gt;4. node format
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;2. tree clients
   &lt;ul&gt;
     &lt;li&gt;0. regular file
     &lt;/li&gt;&lt;li&gt;1. tail to extent conversion
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;3. transaction engine
   &lt;ul&gt;
     &lt;li&gt;0. goals: atomicity, no isolation, durability
     &lt;/li&gt;&lt;li&gt;1. log structure
     &lt;/li&gt;&lt;li&gt;2. shadow updates
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;4. directory code
   &lt;ul&gt;
     &lt;li&gt;0. overview of hashed directories
     &lt;/li&gt;&lt;li&gt;1. key structure and its motivation
     &lt;/li&gt;&lt;li&gt;2. lookup readdir
     &lt;/li&gt;&lt;li&gt;3. NFS?
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;5. delayed allocation and the flush algorithm
   &lt;ul&gt;
     &lt;li&gt;0. delayed allocation motivation
     &lt;/li&gt;&lt;li&gt;1. flush algorithm
     &lt;/li&gt;&lt;li&gt;2. overview of interaction with VM
     &lt;/li&gt;&lt;li&gt;3. emergency flush
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/li&gt;&lt;li&gt;6. round up
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;0. trivia&lt;/h4&gt;
&lt;div class="kernel"&gt;
&lt;p&gt;
&lt;a href="http://namesys.com/v4/v4.html"&gt;Reiser4&lt;/a&gt; is a relatively new
file system for Linux developed by &lt;a href="http://namesys.com"&gt;namesys&lt;/a&gt;. Its development started early in 2001, and currently reiser4 is included into &lt;a href="ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6"&gt;-mm&lt;/a&gt; patch series. Reiser4 is a next version of well-known reiserfs v3 file system (also known as simply reiserfs) that was first and for a long time the only journalled file system for Linux. While reiser4 is based on the same basic architectural ideas as reiserfs v3 it was written completely from scratch and its on-disk format is not compatible with reiserfs. Note on naming: namesys insists that file system is referred to as reiser4 and not reiserfs v4, or reiser4fs, or reiserfs4, or r4fs. Development of reiser4 was sponsored by &lt;a href="http://darpa.mil"&gt;DARPA&lt;/a&gt;, take a look at the namesys front page for a legal statement, and a list of other sponsors.
&lt;/p&gt;&lt;p&gt;
Technically speaking reiser4 can be briefly discussed as a file system using
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;global shared balanced lazily compacted tree to store all data and meta-data
 &lt;/li&gt;&lt;li&gt;bitmaps for block allocation
 &lt;/li&gt;&lt;li&gt;redo-only WAL (write ahead logging) with shadows updates (called "wandered logs" in reiser4)
 &lt;/li&gt;&lt;li&gt;delayed allocation in parent-first tree ordering
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;
I shall (hopefully) describe these topics in more details in the future entries.
&lt;/p&gt;&lt;p&gt;
One last trivia point: I was amongst reiser4 &lt;a href="http://namesys.com/devels.html"&gt;developers&lt;/a&gt; from the very beginning of this project. At the mid-2004 I left namesys, at that point reiser4 was in more or less debugged state, and no significant design changes occurred since.
&lt;/p&gt;
&lt;/div&gt;

&lt;h4&gt;1. reiser4 strong points&lt;/h4&gt;
&lt;div class="kernel"&gt;

&lt;p&gt;
Together with the unique design, reiser4 inherited reiserfs' strengths and weaknesses:
&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;efficient support for very small files: multiple small files can be stored in the same disk block. This saves disk space, and &lt;em&gt;much more importantly&lt;/em&gt; IO traffic between secondary and primary storage;
 &lt;/li&gt;&lt;li&gt;support for very large directories: due to balanced tree (to be described later), file system can handle directories with hundreds of million of files. The utility of this (and small files support) is often questioned, because "nobody uses file system in that way". Reiser4 design is based on the assumption, that cause-and-effect goes in the opposite direction here: applications do not use large directories and small files precisely because existing file system didn't provide efficient means for this. Instead, application developers had to resort to various hacks from configuration files (that have obvious hierarchical structure asking for being mapped onto file system), to artificially splitting large directory into smaller ones (look at &lt;a href="file:///usr/share/terminfo/"&gt;/usr/share/terminfo/&lt;/a&gt; directory as an example);
 &lt;/li&gt;&lt;li&gt;no hard limit on the number of objects on the file system. Traditional UNIX file systems (s5fs,ffs,ufs,ext2,ext3) fix total number of objects that can exist on a file system during file system creation. Correct estimation of this number is a tricky business. Reiser4, on the other hand, creates on-disk inodes (called "stat data" for historical reasons) dynamically;
 &lt;/li&gt;&lt;li&gt;previous item can be seen as a weakness, because it means that reiser4 on-disk format is more complex than that of its brethren. Other advanced reiser4 features also come not without an increase of format complexity. As a result, reiser4 can be corrupted in much more complicated ways than other file systems, requiring quite sophisticated fsck.
&lt;/li&gt;&lt;/ul&gt;

&lt;/div&gt;
   
&lt;h4&gt;2. architecture overview&lt;/h4&gt;
&lt;div class="kernel"&gt;

&lt;p&gt;
As was already hinted above reiser4 is quite different from other file systems architecturally. The most important difference, perhaps, is that reiser4 introduces another layer ("storage layer") between file system and block device. This layer provides an abstraction of persistent "container" into which pieces of data (called "units") can be placed and later retrieved. Units are identified by "keys": when unit is placed into container a key is given, and unit can later be retrieved by providing its key. Unit key is just a fixed-length sequence of bits.
&lt;/p&gt;&lt;p&gt;
In reiser4 this container abstraction is implemented in a form of special flavor of &lt;a href="http://en.wikipedia.org/wiki/B_tree"&gt;B-tree&lt;/a&gt;. There is one instance of such tree (referred to as "internal tree") per file system.
&lt;/p&gt;&lt;p&gt;
Entities from which file system is composed (regular files, directories, symlinks, on-disk inodes, etc.) are stored in the internal tree as sequences of units.
&lt;/p&gt;&lt;p&gt;
In addition to presenting container abstraction, storage layer is responsible for block allocation. That is, as units are inserted and deleted, tree grows and shrinks, taking blocks from block allocator and returning them back. Block allocation policy implemented by storage layer is very simple: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;units with close keys are kept as close on disk as possible, and 
 &lt;/li&gt;&lt;li&gt;units should be placed in the disk blocks so that key ordering corresponds to the block ordering on disk.
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;
This allows higher layers of the system to influence location of units on disk by selecting unit keys appropriately. 
&lt;/p&gt;&lt;p&gt;
While this doesn't sound especially exciting, key-based block allocation allows reiser4 to implement one extremely important feature: global block allocation policies. For example, by assigning to units of all objects in a given directory keys with the same prefix, higher layer code can assure that all objects located in this directory will be located close to each other on the disk. Moreover, by selecting next few bits of key based on --say-- file name it is possible to arrange all objects in the directory in the same order as readdir returns their names, so that commands like
&lt;/p&gt;

&lt;div class="code"&gt;
$ cp -a * /somewhere
&lt;/div&gt;

&lt;p&gt;
will not cause a single seek during read. More on this in the section on "delayed allocation and the flush algorithm".
&lt;/p&gt;&lt;p&gt;
So the highest layer in reiser4 implements file system semantics using storage layer as a container. Storage layer uses block allocator to manage disk space and transaction engine to keep file system consistent in case of a crash. Transaction layer talks to block device layer to send data to the storage.
&lt;/p&gt;
&lt;/div&gt;

To Be Continued by: internal tree.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113494322028231145?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113494322028231145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113494322028231145' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113494322028231145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113494322028231145'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/12/reiser4-0-introduction.html' title='reiser4: 0. introduction'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113277594765364268</id><published>2005-11-23T19:45:00.000Z</published><updated>2005-11-23T21:17:33.546Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>opahead patch</title><content type='html'>&lt;div class="kernel"&gt;
&lt;p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.15-rc1/0b-opahead.patch"&gt;Here&lt;/a&gt; is a 2.6.15-rc1 version of &lt;em&gt;opahead&lt;/em&gt; patch that was sleeping in my &lt;a href="http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20/"&gt;patch-scripts&lt;/a&gt; series file for some time.
&lt;/p&gt;&lt;p&gt;
&lt;em&gt;opahead&lt;/em&gt; stands for &lt;i&gt;operation-ahead&lt;/i&gt; by analogy with read-ahead. An inspiration for this patch was a &lt;a href="http://www.usenix.org/events/usenix01/kroeger.html"&gt;USENIX paper&lt;/a&gt; that discusses a smarter than usual read-ahead algorithm. Kroeger and Long implemented a  sub-system that kept track of read accesses to files and, according to certain stochastic model uses collected information to try to predict future accesses.
&lt;/p&gt;&lt;p&gt;
opahead uses much simpler model known as &lt;i&gt;Shannon Oracle&lt;/i&gt;. (Unfortunately, I failed to find any online reference. I read a description of this algorithm many years ago in a book I no longer have.) It basically maintains enough data to answer following question: for a given sequence of N reads, what reads have been seen to follow this sequence in the past and how many times? Read that followed the sequence most, is assumed to be most likely to happen, and appropriate read-ahead is issued.
&lt;/p&gt;&lt;p&gt;
If N equals 1 we get familiar &lt;a href="http://en.wikipedia.org/wiki/Markov_Chain"&gt;Markov Chain&lt;/a&gt; model. This is why the patch is sometimes called &lt;i&gt;Markov read-ahead&lt;/i&gt;. But Markov chains have one fundamental disadvantage that makes them unsuitable for the read-ahead implementation: to make efficient read-ahead it's necessary to saturate IO layer and for this one has to look &lt;em&gt;more than one&lt;/em&gt; event ahead in the future. That is, we have to predict next read, then assume that it did happen, and made new prediction based on that assumption. Obviously, the reliability of consecutive predictions deteriorates quickly, so it's very important to make initial prediction as reliable as possible. To this end, predictions are made on the basis of N previous reads, rather than on the basis of single one as in Markov
model.
&lt;/p&gt;&lt;p&gt;
Another observation is that this algorithm doesn't depend on the nature of the events that are tracked and predicted. It can be generalized to the module that tracks and predicts abstract events that can be compared for equality (and it is that generalized form that is implemented in the patch).
&lt;/p&gt;&lt;p&gt;
That module can be used to do read-ahead at the different layers: VFS, file system, VM (page cache read-ahead), block layer (physical read-ahead); or it can be used for things completely unrelated to the read-ahead like, god forbid... predicting scheduling activity..
&lt;/p&gt;&lt;p&gt;
This patch was used to drive read-ahead at the file system layer (by plugging calls to &lt;tt&gt;opahead_{happens,predict}()&lt;/tt&gt; into ext2_file_read()), but even though speed up of kernel compilation was measurable, this turned out to be dead-end, because to read a page from file one has to bring inode it memory first, but currently there is no an API for asynchronous inode loading.
&lt;/p&gt;&lt;p&gt;
Below is a top-level comment from &lt;tt&gt;opahead.h&lt;/tt&gt; header with the general
description of API (at least my effort of typing it in wouldn't be wasted).

&lt;div class="code-title"&gt;opahead API&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
/*
 * This file is an interface to the op-ahead: a generic prediction engine.
 *
 * op-ahead implementation is in lib/opahead.c
 *
 * General description.
 *
 * op-ahead makes predictions in a certain domain consisting of events. Events
 * happen sequentially. op-head clients notify engine about events that
 * happen, and engine keeps track of event patterns. Engine then can be asked
 * a question: "Given a sequence of N last events, what is the next event to
 * happen most likely?"
 *
 * To answer this question, op-ahead keeps track of all sequences of N events
 * ever observed in the domain. N is called domain depth, and said sequences
 * are called paths. For each path op-ahead maintains a list of events that
 * were observed to follow this path (that is, to happen immediately after
 * events in the path happened in order). These following events (called
 * guesses) are weighted: the weight is a guess is a number of times it was
 * observed to follow this path.
 *
 * op-ahead operation is quite simple: when event E happens, op-ahead finds a
 * path corresponding to last happened events, and increases the weight of
 * guess corresponding to E (creating new guess if necessary).
 *
 * When asked to predict what event will follow given N events, op-ahead finds
 * path corresponding to these events and returns the guess with the largest
 * weight. If there are multiple guesses with the equal weight---random one is
 * selected.
 *
 * When domain depth is 1, paths degenerate into events and op-ahead into
 * modeling Markov chains.
 *
 * op-ahead algorithm is known as "Shannon Oracle". It is reported that in the
 * domain of two events "tail" and "head", and with the depth of 5, Shannon
 * Oracle robustly beats human player in the game of head and tails (that is,
 * after some period of learning it's able to predict next move with the
 * probability higher than 0.5). You are hereby requested to spend at least 10
 * percent of proceeds obtained from playing head and tails with the help of
 * this kernel code to buy hardware and to provide it to Linux kernel
 * developers.
 *
 * Usage.
 *
 * To use op-ahead client creates an instance of struct opa_domain with
 * methods appropriate for its events.
 *
 * Predictions are made in the "context" which is an array of domain-&gt;depth
 * pointers to events. This context is created by client (initialized by NULL
 * pointers) and is passed to opa_{predict,happen}(). It is used to record
 * latest events. When context is no longer needed, client calls
 * opa_context_put().
 *
 * When new event happens, client calls opa_happens() to record it. To predict
 * future events opa_predict() is used.
 *
 * Related work.
 *
 * In http://www.usenix.org/events/usenix01/kroeger.html a similar (albeit
 * more mathematically sophisticated) model is used to predict future file
 * accesses and to drive inter-file read-ahead.
 *
 * TODO:
 *
 * Helper functions for reference-counted events.
 *
 */
&lt;/pre&gt;
&lt;/div&gt;

&lt;b&gt;To be Continued?&lt;/b&gt;

&lt;/div&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Filesystems" rel="tag"&gt;Filesystems&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113277594765364268?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113277594765364268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113277594765364268' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113277594765364268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113277594765364268'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/11/opahead-patch.html' title='opahead patch'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113181346005818352</id><published>2005-11-12T16:35:00.000Z</published><updated>2005-11-16T15:15:00.916Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>An exercise</title><content type='html'>&lt;p&gt;
Here is a little problem. Given an array &lt;span class="math"&gt;A&lt;/span&gt; of &lt;span class="math"&gt;N&lt;/span&gt; integers, find a sub-array (determined by a pair of
indices within &lt;span class="math"&gt;A&lt;/span&gt;) such that sum of elements in that
sub-array is maximal among all sub-arrays of &lt;span class="math"&gt;A&lt;/span&gt;.
&lt;/p&gt;
&lt;p&gt;
Sounds pretty easy? It is, but just to set a little standard for solutions:
there is a way (shown to me by 15-year-old boy) to do this in one pass over &lt;span class="math"&gt;A&lt;/span&gt; and without using any additional storage except for few
integer variables.
&lt;/p&gt;
&lt;p&gt;
So much for dynamic programming...
&lt;/p&gt;

&lt;h4&gt;update&lt;/h4&gt;

That exercise is interesting, because while superfluously similar to the
well-known tasks like finding longest common substring, etc. it can be solved
in one pass.

Indeed Matti &lt;a href="http://nikitadanilov.blogspot.com/2005/11/exercise.html#113183576990722370"&gt;presented&lt;/a&gt; exactly the same solution that I had in mind. And it is
possible (and instructive) to get a rigorous proof that this algorithm solves
the problem.

&lt;div class="code-title"&gt;Definition 0&lt;/div&gt;
&lt;div class="code"&gt;
Let &lt;span class="math"&gt;A = (i, j)&lt;/span&gt; be a sub-array &lt;span class="math"&gt;(i &lt;= j)&lt;/span&gt;, then &lt;span class="math"&gt;S(A) = S(i, j)&lt;/span&gt; denotes a sum of elements in &lt;span class="math"&gt;A&lt;/span&gt;. &lt;span class="math"&gt;S(A)&lt;/span&gt; will be called &amp;#8222;&lt;em&gt;sum of &lt;span class="math"&gt;A&lt;/span&gt;&lt;/em&gt;&amp;#8220;
&lt;/div&gt;&lt;br&gt;

&lt;div class="code-title"&gt;Definition 1&lt;/div&gt;
&lt;div class="code"&gt;
Let &lt;span class="math"&gt;A = (i, j)&lt;/span&gt; be a sub-array &lt;span class="math"&gt;(i &lt;= j)&lt;/span&gt;, then for any

&lt;div class="mathout"&gt;0 &lt;= p &lt; i &lt; q &lt; j &lt; r &lt; N&lt;/div&gt;

sub-array &lt;span class="math"&gt;(p, i - 1)&lt;/span&gt; is called left outfix of &lt;span class="math"&gt;A&lt;/span&gt;, &lt;span class="math"&gt;(i, q)&lt;/span&gt; --- left infix of &lt;span class="math"&gt;A&lt;/span&gt;, &lt;span class="math"&gt;(q + 1, j)&lt;/span&gt; --- right infix of &lt;span class="math"&gt;A&lt;/span&gt;, and &lt;span class="math"&gt;(j + 1, r)&lt;/span&gt; --- right outfix of &lt;span class="math"&gt;A&lt;/span&gt;.
&lt;/div&gt;&lt;br&gt;

&lt;div class="code-title"&gt;Definition 2&lt;/div&gt;
&lt;div class="code"&gt;
A sub-array is called &lt;em&gt;optimal&lt;/em&gt; if all its infixes have positive sums, and all its outfixes have negative sums.
&lt;/div&gt;&lt;br&gt;

It's easy to prove the following:

&lt;div class="code-title"&gt;Statement 0&lt;/div&gt;
&lt;div class="code"&gt;
A sub-array with the maximal sum is optimal.
&lt;/div&gt;&lt;br&gt;

Indeed, any non-optimal sub-array by definition has either negative infix, or positive prefix, and, hence, can be shrunken or expanded to another sub-array that has larger sum.

As an obvious corollary we get:

&lt;div class="code-title"&gt;Statement 1&lt;/div&gt;
&lt;div class="code"&gt;
To find a sub-array with the maximal sum it's enough to find a sub-array with the maximal sun among all optimal sub-arrays.
&lt;/div&gt;&lt;br&gt;

The key fact that explains why our problem can be solved in one pass is captured in the following:

&lt;div class="code-title"&gt;Statement 2&lt;/div&gt;
&lt;div class="code"&gt;
Optimal sub-arrays are not overlapping.
&lt;/div&gt;&lt;br&gt;

Also easily proved by observing that when two sub-arrays &lt;span class="math"&gt;A&lt;/span&gt; and &lt;span class="math"&gt;B&lt;/span&gt; overlap there
always is an sub-array &lt;span class="math"&gt;C&lt;/span&gt; that is an infix of &lt;span class="math"&gt;A&lt;/span&gt; and an outfix of &lt;span class="math"&gt;B&lt;/span&gt;.

And, now the only thing left to do is to prove that Matti's algorithm
calculates sums of (at least) all optimal sub-arrays. Which is easy to do:

&lt;ul&gt;
  &lt;li&gt;first prove that possibly except for the initial value, &lt;span class="math"&gt;new_start&lt;/span&gt; always points to the index at which at least one (and, therefore, exactly one) optimal array starts. This is easily proved by induction.&lt;/li&gt;
  &lt;li&gt;then prove that once particular value of &lt;span class="math"&gt;new_start&lt;/span&gt; has been reached, &lt;span class="math"&gt;new_start&lt;/span&gt; is not modified until &lt;span class="math"&gt;i&lt;/span&gt; reaches upper index of optimal array starting at &lt;span class="math"&gt;new_start&lt;/span&gt;. This follows directly from the definition of optimal sub-array, because all its left infixes have positive sums.&lt;/li&gt;
  &lt;li&gt;this means that for any optimal sub-array &lt;span class="math"&gt;(p, q)&lt;/span&gt; there is an iteration of the loop at which

&lt;div class="mathout"&gt;new_start == p &amp;&amp; i == q&lt;/div&gt;

 As algorithm finds maximal sum among all &lt;span class="math"&gt;(new_start, i)&lt;/span&gt; sub-arrays, it finds maximal sum among all optimal arrays, and, by &lt;span class="math"&gt;Statement 1&lt;/span&gt;, maximal sum among all sub-arrays.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;------------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113181346005818352?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113181346005818352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113181346005818352' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113181346005818352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113181346005818352'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/11/exercise.html' title='An exercise'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113015226160814830</id><published>2005-10-24T10:02:00.001Z</published><updated>2005-10-24T11:14:37.976Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Update of my kernel patches for 2.6.14-rc5</title><content type='html'>&lt;div class="kernel"&gt;
&lt;p&gt;
   New version of patches is uploaded &lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5"&gt;here&lt;/a&gt;.
 &lt;/p&gt;&lt;p&gt;
   This series include:
 &lt;dl&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/01-skip-writepage.patch"&gt;vm_02-skip-writepage.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Don't call -&gt;writepage from VM scanner when page is met for the first time
during scan.
&lt;/p&gt;&lt;p&gt;
New page flag PG_skipped is used for this. This flag is TestSet-ed just
before calling -&gt;writepage and is cleaned when page enters inactive
list.
&lt;/p&gt;&lt;p&gt;
One can see this as &amp;#8222;second chance&amp;#8220; algorithm for the dirty pages on the
inactive list.
&lt;/p&gt;&lt;p&gt;
BSD does the same: src/sys/vm/vm_pageout.c:vm_pageout_scan(),
PG_WINATCFLS flag.
&lt;/p&gt;&lt;p&gt;
Reason behind this is that -&gt;writepages() will perform more efficient writeout
than -&gt;writepage(). Skipping of page can be conditioned on zone-&gt;pressure.
&lt;/p&gt;&lt;p&gt;
On the other hand, avoiding -&gt;writepage() increases amount of scanning
performed by kswapd.
&lt;/p&gt;&lt;p&gt;
(Possible drawback: executable text pages are evicted earlier.)
&lt;/p&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/02-__alloc_pages-inject-failure.patch"&gt;vm_04-__alloc_pages-inject-failure.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Force artificial failures in page allocator. I used this to harden some kernel code.
&lt;/p&gt;
   &lt;/dt&gt;

 &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/03-async-writepage.patch"&gt;async-writepage.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;&lt;dt&gt;&lt;p&gt;

Perform calls to the -&gt;writepage() asynchronously.
&lt;/p&gt;&lt;p&gt;
VM scanner starts pageout for dirty pages found at tail of the inactive list
during scan. It is supposed (or at least desired) that under normal conditions
amount of such write back is small.
&lt;/p&gt;&lt;p&gt;
Even if few pages are paged out by scanner, they still stall "direct reclaim"
path (__alloc_pages() -&gt; try_to_free_pages() -&gt; ... -&gt; shrink_list() -&gt; writepage()),
and to decrease allocation latency it makes sense to perform pageout
asynchronously.
&lt;/p&gt;&lt;p&gt;
Current design is very simple: asynchronous page-out is done through pdflush
operation kpgout(). If shrink_list() decides that page is eligible for the
asynchronous pageout, it is placed into shared queue and later processed by
one of pdflush threads.
&lt;/p&gt;&lt;p&gt;
Most interesting part of this patch is async_writepage() that decides when
page should be paged out asynchronously. Currently this function allows
asynchronous writepage only from direct reclaim, only if zone memory pressure
is not too high, and only if expected number of dirty pages in the scanned
chunk is larger than some threshold: if there are only few dirty pages on the
list, context switch to the pdflush outwieghts advantages of asynchronous
writepage.

 &lt;/p&gt;&lt;/dt&gt;

   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/04-page_referenced-move-dirty.patch"&gt;vm_05-page_referenced-move-dirty.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
transfer dirtiness from pte to the struct page in page_referenced(). This
makes pages dirtied through mmap &amp;#8222;visible&amp;#8220; to the file system, that can write
them out through -&gt;writepages() (otherwise pages are written from
-&gt;writepage() from tail of the inactive list).
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/05-cluster-pageout.patch"&gt;vm_06-cluster-pageout.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Implement pageout clustering at the VM level.
&lt;/p&gt;&lt;p&gt;
With this patch VM scanner calls pageout_cluster() instead of
-&gt;writepage(). pageout_cluster() tries to find a group of dirty pages around
target page, called &amp;#8222;pivot&amp;#8220; page of the cluster. If group of suitable size is
found, -&gt;writepages() is called for it, otherwise, page_cluster() falls back
to -&gt;writepage().
&lt;/p&gt;&lt;p&gt;
This is supposed to help in work-loads with significant page-out of
file-system pages from tail of the inactive list (for example, heavy dirtying
through mmap), because file system usually writes multiple pages more
efficiently. Should also be advantageous for file-systems doing delayed
allocation, as in this case they will allocate whole extents at once.
&lt;/p&gt;&lt;p&gt;
Few points:
&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt; swap-cache pages are not clustered (although they can be, but by
   page-&gt;private rather than page-&gt;index) &lt;/li&gt;

 &lt;li&gt; only kswapd do clustering, because direct reclaim path should be low
   latency.&lt;/li&gt;

 &lt;li&gt; Original version of this patch added new fields to struct writeback_control
   and expected -&gt;writepages() to interpret them. This led to hard-to-fix races
   against inode reclamation. Current version simply calls -&gt;writepage() in the
   "correct" order, i.e., in the order of increasing page indices..&lt;/li&gt;
&lt;/ul&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/06-proc-stack.patch"&gt;vm_07-proc-stack.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Export kernel backtrace in &lt;tt&gt;/proc/&amp;lt;pid&amp;gt;/task/&amp;lt;tid&amp;gt;/stack&lt;/tt&gt;. Useful when debugging
deadlocks.
&lt;/p&gt;&lt;p&gt;

This somewhat duplicates functionality of SysRq-T, but is less intrusive to
the system operation and can be used in the scripts.
&lt;/p&gt;&lt;p&gt;

Exporting kernel stack of a thread is probably unsound security-wise. Use with
care.
&lt;/p&gt;&lt;p&gt;

Instead of adding yet another architecture specific function to output thread
stack through seq_file API, it introduces &amp;#8222;iterator&amp;#8220;
&lt;/p&gt;&lt;pre&gt;

void do_with_stack(struct task_struct *tsk, 
     int (*actor)(int, void *, void *, void *), void *opaque)
&lt;/pre&gt;&lt;p&gt;

that has to be implemented by each architecture, so that generic code can
iterate over stack frames in architecture-independent way.
&lt;/p&gt;&lt;p&gt;

lib/do_with_stack.c is provided for archituctures that don't implement their
own. It is based on __builtin_{frame,return}_address().
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/07-proc-sleep.patch"&gt;vm_08-proc-sleep.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
export per-process blocking statistics in &lt;tt&gt;/proc/&amp;lt;pid&amp;gt;/task/&amp;lt;tid&amp;gt;/sleep&lt;/tt&gt; and global sleeping statistics in &lt;tt&gt;/proc/sleep&lt;/tt&gt;. Statistics
collection for given file is activated on the first read of
corresponding &lt;tt&gt;/proc&lt;/tt&gt; file. When statistics collection is on on each context switch
current back-trace is built (through __builtin_return_address()). For each
monitored process there is a LRU list of such back-traces. Useful when trying
to understand where elapsed time is spent.
&lt;/p&gt;
   &lt;/dt&gt;

 &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/08-export-filemap_populate-in-proper-place.patch"&gt;&lt;/a&gt;export-filemap_populate-in-proper-place.patch&lt;/tt&gt;&lt;/dd&gt;&lt;dt&gt;&lt;p&gt;
move EXPORT_SYMBOL(filemap_populate) to the proper place: just after function
itself: it's easy to miss that function is exported otherwise.

 &lt;/p&gt;&lt;/dt&gt;

 &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/09-throttle-against-free-memory.patch"&gt;throttle-against-free-memory.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;&lt;dt&gt;&lt;p&gt;
Fix write throttling to calculate its thresholds from amount of memory that
can be consumed by file system and swap caches, rather than from the total
amount of physical memory. This avoids situations (among other things) when
memory consumed by kernel slab allocator prevents write throttling from ever
happening.
 &lt;/p&gt;&lt;/dt&gt;

 &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.14-rc5/0a-BUILD_BUG_ON-fix-comment.patch"&gt;BUILD_BUG_ON-fix-comment.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;&lt;dt&gt;&lt;p&gt;
Fix comment describing BUILD_BUG_ON: BUG_ON is not an assertion
(unfortunately).

Also implement BUILD_BUG_ON in a way that can be used outside of a function
scope, so that compile time checks can be placed in convenient places (like in
a header, close to the definition of related constants and data-types).
 &lt;/p&gt;&lt;/dt&gt;

 &lt;/dl&gt;
  &lt;/p&gt;&lt;p&gt;
   &lt;tt&gt;zoneinfo.patch&lt;/tt&gt;, &lt;tt&gt;deadline-iosched.c-cleanup.patch&lt;/tt&gt; and &lt;tt&gt;ll_merge_requests_fn-cleanup.patch&lt;/tt&gt; were merged into Linus tree.
 &lt;/p&gt;&lt;p&gt;
   &lt;tt&gt;dont-rotate-active-list.patch&lt;/tt&gt; was dropped: it seems to cause inactive list exhaustion for certain wrodloads.
 &lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Hacking" rel="tag"&gt;Hacking&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel"  rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113015226160814830?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113015226160814830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113015226160814830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113015226160814830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113015226160814830'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/10/update-of-my-kernel-patches-for-2614_24.html' title='Update of my kernel patches for 2.6.14-rc5'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112945795333958935</id><published>2005-10-16T10:15:00.000Z</published><updated>2005-10-16T10:21:34.870Z</updated><title type='text'>Грозный</title><content type='html'>&lt;blockquote&gt;
       "Чешский археолог Бедржих Грозный (1879--1952), который в 1915 г. расшифровал хеттскую клинопись, и именем которого был назван город в южной России."
&lt;/blockquote&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/History" rel="tag"&gt;History&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Quotes" rel="tag"&gt;Quotes&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112945795333958935?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112945795333958935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112945795333958935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112945795333958935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112945795333958935'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/10/blog-post.html' title='Грозный'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112921961792213015</id><published>2005-10-13T16:00:00.000Z</published><updated>2005-10-13T16:11:23.053Z</updated><title type='text'>Get me out of here!</title><content type='html'>&lt;table cellspacing=30&gt;
&lt;tr&gt;
&lt;td&gt;Everything a traveler has to know to get into China and, &lt;em&gt;more importantly&lt;/em&gt;, back.&lt;/td&gt;
&lt;td&gt;Всё, что необходимо знать для путешествия в Китай и обратно.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;center&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/china-back-0.png"&gt;&lt;img src="http://linuxhacker.ru/~nikita/misc/china-back-1.png"&gt;&lt;/a&gt;
&lt;/center&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/China" rel="tag"&gt;China&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;------------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112921961792213015?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112921961792213015/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112921961792213015' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112921961792213015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112921961792213015'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/10/get-me-out-of-here.html' title='Get me out of here!'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112664364411841780</id><published>2005-09-13T19:15:00.000Z</published><updated>2005-09-19T07:33:11.736Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>plug &amp; crash</title><content type='html'>&lt;p&gt; I had some problems in my local network to-day, so I had to turn off the
switch. &lt;em&gt;Bang!&lt;/em&gt; My workstation hang immediately as power cord was
unplugged from the &lt;tt&gt;D-Link&lt;/tt&gt;. Initially I thought that something is
wrong with the grounding, but a series of painful experiments proved that
electricity has nothing to do with this: workstation hung whenever Ethernet
cable was pulled off the socket. This looks like complete &lt;a href="http://www.retrologic.com/jargon/magic-story.html"&gt;magic&lt;/a&gt;&lt;sup&gt;&lt;b&gt;[&lt;/b&gt;&lt;a href="#ether_magic"&gt;1&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;&lt;/sup&gt; isn't it?  Fortunately I was advised
to boot kernel with &lt;tt&gt;nmi_watchdog=1&lt;/tt&gt; (before I went insane, that is),
and with the first stack-trace problem became obvious:
&lt;/p&gt; &lt;ul&gt;
    &lt;li&gt;when cable is pulled, rtl8139 driver receives an interrupt and the
    first thing it does is grabbing of spin-lock, protecting struct
    rtl8139_private...
    &lt;/li&gt;&lt;li&gt;after that it goes to print &amp;#8222;link-down&amp;#8220; message to
    the console...
    &lt;/li&gt;&lt;li&gt;but I am using netconsole&lt;sup&gt;&lt;b&gt;[&lt;/b&gt;&lt;a  href="#ether_netconsole"&gt;2&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;&lt;/sup&gt;, and to
    print that message netconsole calls back into rtl8139 driver...
    &lt;li&gt;and the first thing it does is grabbing of spin-lock... which is
    already grabbed by that very thread---deadlock.
&lt;/ul&gt;
&lt;hr&gt;

&lt;p&gt;
&lt;b&gt;[&lt;/b&gt;1&lt;b&gt;]&lt;/b&gt; when I'll have a time, I'll also record a true story
that happened during reiserfs debugging: how saving file in emacs made all
processes in the system invisible to ps(1) and top(1).  &lt;/p&gt;

&lt;p&gt;
&lt;b&gt;[&lt;/b&gt;2&lt;b&gt;]&lt;/b&gt; a console driver that sends kernel messages over network in
UDP packets---very useful for debugging.
&lt;/p&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Networking" rel="tag"&gt;Networking&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112664364411841780?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112664364411841780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112664364411841780' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112664364411841780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112664364411841780'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/09/plug-crash.html' title='plug &amp; crash'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112490350408615806</id><published>2005-08-24T15:06:00.000Z</published><updated>2005-09-26T10:17:13.400Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>A look at several memory management units...</title><content type='html'>&lt;p&gt;
An interesting &lt;a href="http://www.engr.umd.edu/~blj/papers/asplos98.pdf"&gt;paper&lt;/a&gt; (via &lt;a
href="http://www.livejournal.com/users/mulix/157621.html"&gt;Muli
Ben-Yehuda&lt;/a&gt;) that describes, in particular, VM organization of
several platforms. A bit I didn't knew: ULTRIX uses two level page tables
that are traversed &lt;em&gt;bottom-up&lt;/em&gt;: leaf level of the tree lives in
the virtual space and is contiguous in it. As a result, to handle TLB
miss at the virtual address A it's enough to do:
&lt;/p&gt;
&lt;div class="code-title"&gt;ULTRIX page-fault handler. V0&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
        phys_address = LEAF_TABLE[A &gt;&gt; PTABLE_SHIFT_LEAF];
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Obviously it is somewhat more involved in reality, because appropriate
portion of LEAF_TABLE[] can be not in the TLB itself. In the latter
case, root node of the tree is consulted:
&lt;/p&gt;

&lt;div class="code-title"&gt;ULTRIX page-fault handler. V1&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
        if (tlb_miss(LEAF_TABLE + (A &gt;&gt; PTABLE_SHIFT_LEAF))
                tlb_load(ROOT_NODE[A &gt;&gt; PTABLE_SHIFT_ROOT],
                         LEAF_TABLE + (A &gt;&gt; PTABLE_SHIFT_LEAF));
        phys_address = LEAF_TABLE[A &gt;&gt; PTABLE_SHIFT_LEAF];
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Root node is wired down into unmapped (physical) memory.
&lt;/p&gt;

&lt;p&gt; This design provides following advantages: &lt;/p&gt;

&lt;ul&gt;

   &lt;li&gt;TLB miss handling requires one memory access in the best case,
and two in the worst. In top-to-bottom page tables &lt;i&gt;a la&lt;/i&gt; Intel,
two (or three) accesses are necessary for every TLB refill;&lt;/li&gt;
   &lt;li&gt;This integrates nicely with virtually indexed processor caches;&lt;/li&gt;
   &lt;li&gt;This allows parts of page tables to be paged out easily.&lt;/li&gt;
&lt;/ul&gt;

Unfortunately Digital screwed this design by using slow software filled
TLB.

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/VM" rel="tag"&gt;VM&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112490350408615806?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112490350408615806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112490350408615806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112490350408615806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112490350408615806'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/look-at-several-memory-management.html' title='A look at several memory management units...'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112435483352334549</id><published>2005-08-18T08:38:00.000Z</published><updated>2005-11-02T22:18:42.586Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>named formals</title><content type='html'>Another C99 abuse: &amp;#8222;&lt;i&gt;named formal parameters&lt;/i&gt;&amp;#8220;:

&lt;div class="code-title"&gt;named formal parameters&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
int foo(int a, char b)
{
        printf("foo: a: %i, b: %c (%i)\n", a, b, b);
}

/* 
 * NOTE: imagine that following macro definition is properly backslashified.
 *       And blame Google/Blogger for my not being able to do this.
 */
#define foo(...) ({                 
          struct {                  
                   int  a;          
                   char b;          
          } __fa = { __VA_ARGS__ }; 
          foo(__fa.a, __fa.b);      
})

int main(int argc, char **argv)
{
        foo(.b = 'b', .a = 42);
        foo();
}
&lt;/pre&gt;
&lt;/div&gt;

This outputs:

&lt;pre&gt;
foo: a: 42, b: b (98)
foo: a: 0, b:  (0)
&lt;/pre&gt;

By combining compound literals and &lt;tt&gt;__VA_ARGS__&lt;/tt&gt; (&lt;a href="http://nikitadanilov.blogspot.com/2005/07/vaargs-c99-compound-literals-safe.html"&gt;again&lt;/a&gt;!) it is possible to explicitly name function arguments, specify them in arbitrary order, and omit some of them (omitted arguments are initialized by corresponding default initializers).

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/C" rel="tag"&gt;C&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112435483352334549?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112435483352334549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112435483352334549' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112435483352334549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112435483352334549'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/named-formals.html' title='named formals'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112387784297234309</id><published>2005-08-12T20:17:00.000Z</published><updated>2005-08-12T20:23:14.063Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>A monster desktop</title><content type='html'>&lt;p&gt;
Screenshot of my desktop while running 5 node &lt;a href="http://user-mode-linux.sourceforge.net"&gt;UML&lt;/a&gt; cluster:

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2329/234/1600/screenshot-uml-cluster-2.jpg"&gt;&lt;img src="http://photos1.blogger.com/blogger/2329/234/320/screenshot-uml-cluster-2.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/UML" rel="tag"&gt;UML&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Desktop" rel="tag"&gt;Desktop&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112387784297234309?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112387784297234309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112387784297234309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112387784297234309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112387784297234309'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/monster-desktop.html' title='A monster desktop'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112379745917484967</id><published>2005-08-11T20:42:00.000Z</published><updated>2005-08-11T22:10:49.300Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>kernel stack overflow.</title><content type='html'>&lt;p&gt;

Linux kernel traditionally has very spartan run-time
environment. This is because kernel code is only written by real
programmers, impeccable thinkers with boundless capacity for analysis,
like yours... err, I got carried away.

&lt;/p&gt;&lt;p&gt;

In particular, in good old days, when world was simpler, kernel thread
stack size used to be just 8K (two 4K pages) on x86. As kernel grew
larger, and started to employ more complex algorithms, kernel stack of
course shrunk. Right---&lt;i&gt;shrunk&lt;/i&gt;: now it is 4K (one page) by
default. This was justified by the following considerations:

&lt;/p&gt;
&lt;ul&gt;

    &lt;li&gt;In newer kernels, interrupts can be served on special
per-processor interrupt stack (not all architectures allow this,
though).

    &lt;/li&gt;&lt;li&gt;Linux &lt;a href="http://citeseer.ist.psu.edu/bonwick94slab.html"&gt;slab allocator&lt;/a&gt; is efficient and scalable enough to dynamically allocate many data-structures that used to be allocated on the stack.

    &lt;/li&gt;&lt;li&gt;Main reason is that allocation of stacks larger than page
size --which is the basic allocation unit of low-level buddy allocator--,
fragments page allocator bitmaps, and can lead to out-of-memory
situations. With large number of threads this problems becomes
severe.&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;But I digressed again: to-day I got stack overflow in &lt;a href="http://user-mode-linux.sourceforge.net"&gt;UML&lt;/a&gt; configured with &lt;tt&gt;CONFIG_KERNEL_STACK_ORDER=3&lt;/tt&gt;, that is with stack occupying &lt;span class="math"&gt;2**3 = 8&lt;/span&gt; pages (32K)!:
&lt;/p&gt;
&lt;div class="code-title"&gt;stack&lt;/div&gt;
&lt;div class="code"&gt;
0xa005632c __alloc_pages+636&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa0056427 __get_free_pages+39&lt;br&gt;
0xa00599d8 cache_grow+152&lt;br&gt;
0xa0059d48 cache_alloc_refill+312&lt;br&gt;
0xa005a0cd __kmalloc+125&lt;br&gt;
0xa01a0e58 alloc_skb+72&lt;br&gt;
0xa00257e6 uml_net_rx+38&lt;br&gt;
0xa002595f uml_net_interrupt+47&lt;br&gt;
0xa0016b05 handle_IRQ_event+53&lt;br&gt;
0xa0016cb6 do_IRQ+118&lt;br&gt;
0xa001748a sigio_handler+218&lt;br&gt;
0xa0021b31 sig_handler_common_tt+161&lt;br&gt;
0xa001bf20 enable_mask+80&lt;br&gt;
0xa001de48 sig_handler+24&lt;br&gt;
0xa0217098 __restore&lt;br&gt;
0xa0217212 __sigprocmask+34&lt;br&gt;
0xa001bdda change_sig+90&lt;br&gt;
0xa001be63 change_signals+115&lt;br&gt;
0xa00173ed sigio_handler+61&lt;br&gt;
0xa0021b31 sig_handler_common_tt+161&lt;br&gt;
0xa001de48 sig_handler+24&lt;br&gt;
0xa0217098 __restore&lt;br&gt;
0xa0217212 __sigprocmask+34&lt;br&gt;
0xa001bf20 enable_mask+80&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa001c011 set_signals+129&lt;br&gt;
0xa001be63 change_signals+115&lt;br&gt;
0xa001bf20 enable_mask+80&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa001c011 set_signals+129&lt;br&gt;
0xa001bf68 get_signals+40&lt;br&gt;
0xa005a098 __kmalloc+72&lt;br&gt;
0xa01a0e58 alloc_skb+72&lt;br&gt;
0xa01d2062 tcp_send_ack+50&lt;br&gt;
0xa01cdb04 tcp_rcv_established+612&lt;br&gt;
0xa01d67da tcp_v4_do_rcv+282&lt;br&gt;
0xa01d6e0c tcp_v4_rcv+1580&lt;br&gt;
0xa001bf20 enable_mask+80&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa01bb21a ip_local_deliver+282&lt;br&gt;
0xa01bb706 ip_rcv+870&lt;br&gt;
0xa01a62c5 netif_receive_skb+389&lt;br&gt;
0xa01a63a7 process_backlog+135&lt;br&gt;
0xa01a64b6 net_rx_action+118&lt;br&gt;
0xa003c1b5 __do_softirq+165&lt;br&gt;
0xa003c205 do_softirq+69&lt;br&gt;
0xa0016d0b do_IRQ+203&lt;br&gt;
0xa001748a sigio_handler+218&lt;br&gt;
0xa0021b31 sig_handler_common_tt+161&lt;br&gt;
0xa001be63 change_signals+115&lt;br&gt;
0xa001de48 sig_handler+24&lt;br&gt;
0xa0217098 __restore&lt;br&gt;
0xa0217212 __sigprocmask+34&lt;br&gt;
0xa003c1fe do_softirq+62&lt;br&gt;
0xa0016d0b do_IRQ+203&lt;br&gt;
0xa00173ed sigio_handler+61&lt;br&gt;
0xa0021b31 sig_handler_common_tt+161&lt;br&gt;
0xa001de48 sig_handler+24&lt;br&gt;
0xa0217098 __restore&lt;br&gt;
0xa0217212 __sigprocmask+34&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa001be63 change_signals+115&lt;br&gt;
0xa001bec2 unblock_signals+18&lt;br&gt;
0xa0050aaa find_get_pages_tag+122&lt;br&gt;
0xa005b9d3 pagevec_lookup_tag+51&lt;br&gt;
0xa001bfd5 set_signals+69&lt;br&gt;
0xa001be63 change_signals+115&lt;br&gt;
0xa001bf74 get_signals+52&lt;br&gt;
0xa0058147 mapping_tagged+55&lt;br&gt;
0xa008e841 wake_up_inode+17&lt;br&gt;
0xa00945d1 __sync_single_inode+161&lt;br&gt;
0xa008e387 iput+87&lt;br&gt;
0xa0094932 sync_sb_inodes+450&lt;br&gt;
0xa001c011 set_signals+129&lt;br&gt;
0xa0094af0 writeback_inodes+160&lt;br&gt;
0xa005766a wb_kupdate+186&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa005822f __pdflush+207&lt;br&gt;
0xa001bec2 unblock_signals+18&lt;br&gt;
0xa0058310 pdflush&lt;br&gt;
0xa0058339 pdflush+41&lt;br&gt;
0xa00575b0 wb_kupdate&lt;br&gt;
0xa0058310 pdflush&lt;br&gt;
0xa004aee9 kthread+169&lt;br&gt;
0xa004ae40 kthread&lt;br&gt;
0xa0019909 run_kernel_thread+73&lt;br&gt;
0xa02172e4 sigemptyset+36&lt;br&gt;
0xa004ae40 kthread&lt;br&gt;
0xa00198ee run_kernel_thread+46&lt;br&gt;
0xa004ae40 kthread&lt;br&gt;
0xa001fa50 new_thread_handler+304&lt;br&gt;
0xa004ae40 kthread&lt;br&gt;
0xa001fa90 new_thread_proc&lt;br&gt;
0xa0217098 __restore&lt;br&gt;
0xa001fa90 new_thread_proc&lt;br&gt;
0xa022faad syscall+29&lt;br&gt;
0xa022fab1 syscall+33&lt;br&gt;
&lt;/div&gt;
&lt;p&gt;

Of course, UML is unusual platform: it doesn't support separate
interrupt stack, and interrupt trampoline code (including host signal
frames) is expensive stack-wise, but still: beware of stack consumption.

&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112379745917484967?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112379745917484967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112379745917484967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112379745917484967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112379745917484967'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/kernel-stack-overflow.html' title='kernel stack overflow.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112336536073789439</id><published>2005-08-06T21:34:00.000Z</published><updated>2005-08-06T21:56:00.743Z</updated><title type='text'>Glenn Gould</title><content type='html'>&lt;p&gt;
An absolutely unbelievable thing: on the &lt;i&gt;Variation 24. Canon on the octave&lt;/i&gt;, from 1981 Goldberg Variations performed by Glenn Gould, one can distinctly hear human voice just on the edge of audibility. Glenn Gould is &lt;i&gt;singing&lt;/i&gt; his Bach.
&lt;/p&gt;&lt;p&gt;
Невероятно, но факт: в &lt;i&gt;Вариации 24, канон в октаве&lt;/i&gt;, в исполнении Глена Гоулда 1981-го года, можно, на пороге слышимости различить слабый человеческий голос. Гоулд подпевает.
&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Music" rel="tag"&gt;Music&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Bach" rel="tag"&gt;Bach&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112336536073789439?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112336536073789439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112336536073789439' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112336536073789439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112336536073789439'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/glenn-gould.html' title='Glenn Gould'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112302216152606421</id><published>2005-08-02T22:31:00.000Z</published><updated>2005-08-02T22:36:01.540Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Confessions of Microsoft developer</title><content type='html'>&lt;blockquote&gt;
&lt;a href="http://blogs.msdn.com/larryosterman/archive/2004/08/12/213681.aspx"&gt;As a simple example, when Windows started up, it increased the size of MS-DOS’s internal file table (the SFT, that’s the table that was created by the FILES= line in config.sys).  It did that to allow more than 20 files to be opened on the windows system (a highly desirable goal for a multi-tasking operating system).  But it did that by using an undocumented API call, which returned a pointer to a set of “interesting” pointers in MS-DOS. It then indexed a known offset relative to that pointer, and replaced the value of the master SFT table with its own version of the SFT.  When I was working on MS-DOS 4.0, we needed to support Windows.  Well, it was relatively easy to guarantee that our SFT was at the location that Windows was expecting.  But the problem was that the MS-DOS 4.0 SFT was 2 bytes larger than the MS-DOS 3.1 SFT.   In order to get Windows to work, I had to change the DOS loader to detect when win.com was being loaded, and if it was being loaded, I looked at the code at an offset relative to the base code segment, and if it was a “MOV” instruction, and the amount being moved was the old size of the SFT, I patched the instruction in memory to reflect the new size of the SFT!  Yup, MS-DOS 4.0 patched the running windows binary to make sure Windows would still continue to work.&lt;/a&gt;
&lt;/blockquote&gt;
&lt;p&gt;
And these are the people who &lt;i&gt;design&lt;/i&gt; and implement most widely used software in the world. Which is a scary place indeed.
&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Software" rel="tag"&gt;Software&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112302216152606421?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112302216152606421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112302216152606421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112302216152606421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112302216152606421'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/08/confessions-of-microsoft-developer.html' title='Confessions of Microsoft developer'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112283731540400550</id><published>2005-07-31T19:10:00.000Z</published><updated>2005-07-31T19:15:15.413Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Wikipedia</title><content type='html'>I added a bit of material to the Wikipedia entry on &lt;a href="http://en.wikipedia.org/wiki/Page_replacement_algorithms"&gt;Page replacement algorithms&lt;/a&gt;: a bit of history, precleaning, global vs. local replacement, description of LRU degradation for cyclic access patterns, random replacement, links to the modern algorithms, unification of VM with file system cache, etc. Original entry was more or less re-hash of section from Tannenbaum's &amp;#8222;Operating Systems&amp;#8220;.

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Wikipedia" rel="tag"&gt;Wikipedia&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112283731540400550?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112283731540400550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112283731540400550' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112283731540400550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112283731540400550'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/wikipedia.html' title='Wikipedia'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112283269717336325</id><published>2005-07-31T17:49:00.000Z</published><updated>2005-07-31T18:20:33.706Z</updated><title type='text'>The Question of Life, The Universe, and Everything.</title><content type='html'>&lt;blockquote&gt;
        'How old is that horse, my friend?' inquired Mr. Pickwick,&lt;br&gt;
        rubbing his nose with the shilling he had reserved for the fare.&lt;br&gt;
        &lt;br&gt;
        '&lt;a href="http://en.wikipedia.org/wiki/The_Answer_to_Life%2C_the_Universe%2C_and_Everything"&gt;Forty-two&lt;/a&gt;,' replied the driver, eyeing him askant.&lt;br&gt;
&lt;/blockquote&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/42" rel="tag"&gt;42&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Dickens" rel="tag"&gt;Dickens&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112283269717336325?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112283269717336325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112283269717336325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112283269717336325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112283269717336325'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/question-of-life-universe-and.html' title='The Question of Life, The Universe, and Everything.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112272845786951376</id><published>2005-07-30T12:48:00.000Z</published><updated>2005-11-02T22:20:05.363Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>__VA_ARGS__ + C99 compound literals = safe variadic functions</title><content type='html'>It occurred to me that new C features added by C99 standard can be used to implement &amp;#8222;&lt;i&gt;safe variadic functions&lt;/i&gt;&amp;#8220; that is, something syntactically looking like normal call of function with variable number of arguments, but in effect calling function with all arguments packed into array, and with array size explicitly supplied:

&lt;div class="code-title"&gt;safe variadic functions&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
#define sizeof_array(arr) ((sizeof (arr))/(sizeof (arr)[0]))

/* 
 * NOTE: imagine that following macro definition is properly backslashified.
 *       And blame Google/Blogger for my not being able to do this.
 */
#define FOO(a, ...)
       foo((a), (char *[]){ __VA_ARGS__, 0 }, sizeof_array(((char *[]){ __VA_ARGS__ })))

int foo(int x, char **str, int n)
{
 printf("%i %i\n", x, n);
 while (n--)
  printf("%s\n", *(str++));
 printf("last: %s\n", *str);
}

int main(int argc, char **argv)
{
 FOO(1, "a", "boo", "cooo", "dd", argv[0]);
}
&lt;/pre&gt;
&lt;/div&gt;
this outputs
&lt;pre&gt;
1 5
a
boo
cooo
dd
./a.out
last: (null)
&lt;/pre&gt;
Expect me to use this shortly somewhere.

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/C" rel="tag"&gt;C&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112272845786951376?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112272845786951376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112272845786951376' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112272845786951376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112272845786951376'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/vaargs-c99-compound-literals-safe.html' title='__VA_ARGS__ + C99 compound literals = safe variadic functions'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112233329696639863</id><published>2005-07-25T23:11:00.000Z</published><updated>2005-07-25T23:14:56.966Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Repaging in AIX VM</title><content type='html'>&amp;#8222;&lt;a href="http://www.unet.univie.ac.at/aix/aixbman/prftungd/vmmov.htm"&gt;&lt;i&gt;Repaging&lt;/i&gt;&lt;/a&gt;&amp;#8220; was mentioned to me by Rik van Riel long time ago. How this can be implemented in
Linux? E.g., add &lt;tt&gt;-&gt;repage_tree&lt;/tt&gt; radix-tree to &lt;tt&gt;struct address_space&lt;/tt&gt;. (We get 32
bits per-page this way, while we need only one!) Insert entry into this tree
on each page fault. Do &lt;em&gt;_not_&lt;/em&gt; remove entry when page is reclaimed. As a result,
&lt;tt&gt;-&gt;repage_tree&lt;/tt&gt; keeps history of page faults. Check it on page fault. If there
is an entry for page being faulted in---we have &amp;#8222;repage&amp;#8220;. Maintain global
counter of elements in &lt;tt&gt;-&gt;repage_tree&lt;/tt&gt;'s. When it's higher than some threshold
(AIX uses total number of frames in the primary storage), start removing
&lt;tt&gt;-&gt;repage_tree&lt;/tt&gt; elements on reclaim. Disadvantage: history is lost when &lt;tt&gt;struct
address_space&lt;/tt&gt; is destroyed.

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/AIX" rel="tag"&gt;AIX&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112233329696639863?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112233329696639863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112233329696639863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233329696639863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233329696639863'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/repaging-in-aix-vm.html' title='Repaging in AIX VM'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112233293928107323</id><published>2005-07-25T23:06:00.000Z</published><updated>2005-07-25T23:08:59.283Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>inactive_dirty and inactive_clean are considered harmful</title><content type='html'>Found interesting discussion on linux-mm (Sept. 2002):

&lt;p&gt;
AKPM and Rik (&amp;#8222;inactive_dirty list&amp;#8220;)
&lt;/p&gt;&lt;p&gt;
[AKPM proposed separate inactive_dirty and inactive_clean lists to avoid
excessive scanning of pages that cannot be reclaimed (due to then-new
non-blocking VM scanner]:
&lt;/p&gt;
&lt;pre&gt;
    Riel:
    &gt; AKPM:
    &gt; &gt; - inactive_dirty holds pages which are dirty or under writeback.
    &gt; 
    &gt; &gt; - everywhere where we add a page to the inactive list will now
    &gt; &gt;   add it to either inactive_clean or inactive_dirty, based on
    &gt; &gt;   its PageDirty || PageWriteback state.
    &gt; 
    &gt; If I had veto power I'd use it here ;)
    &gt; 
    &gt; We did this in early 2.4 kernels and it was a disaster. The
    &gt; reason it was a disaster was that in many workloads we'd
    &gt; always have some clean pages and we'd end up always reclaiming
    &gt; those before even starting writeout on any of the dirty pages.
    &gt; 
    &gt; It also meant we could have dirty (or formerly dirty) inactive
    &gt; pages eating up memory and never being recycled for more active
    &gt; data.
&lt;/pre&gt;
And later in the same thread:
&lt;pre&gt;
    AKPM:
    &gt; You're proposing that we get that IO underway sooner if there
    &gt; is page reclaim pressure, and that one way to do that is to
    &gt; write one page for every reclaimed one.  Guess that makes
    &gt; sense as much as anything else ;)
&lt;/pre&gt;
&lt;p&gt;
(decrease dirty cache balancing rules when hitting memory pressure, so that
balance_dirty_pages() and pdflush do write-out in scanner's stead)
&lt;/p&gt;&lt;p&gt;
And further more:
&lt;/p&gt;
&lt;pre&gt;
    Daniel Phillips
    &gt; On Saturday 07 September 2002 01:34, Andrew Morton wrote:
    &gt; &gt; You're proposing that we get that IO underway sooner if there
    &gt; &gt; is page reclaim pressure, and that one way to do that is to
    &gt; &gt; write one page for every reclaimed one.  Guess that makes
    &gt; &gt; sense as much as anything else ;)
    &gt; 
    &gt; Not really.  The correct formula will incorporate the allocation rate
    &gt; and the inactive dirty/clean balance.  The reclaim rate is not
    &gt; relevant, it is a time-delayed consequence of the above.  Relying on
    &gt; it in a control loop is simply asking for oscillation.
&lt;/pre&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112233293928107323?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112233293928107323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112233293928107323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233293928107323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233293928107323'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/inactivedirty-and-inactiveclean-are.html' title='inactive_dirty and inactive_clean are considered harmful'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112233268812834998</id><published>2005-07-25T23:02:00.000Z</published><updated>2005-07-25T23:04:48.130Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>XNU VM</title><content type='html'>&lt;p&gt;
XNU (OSX kernel) VM scanner marks vnodes as (vp-&gt;v_flag &amp; VHASBEENPAGED). write(2) path
checks for this and sends all dirty pages for this vnode down the pipe if this
flags is set. Reason:
&lt;div class="code"&gt;
/*&lt;br&gt;
&amp;nbsp;* this vnode had pages cleaned to it by&lt;br&gt;
&amp;nbsp;* the pager which indicates that either&lt;br&gt;
&amp;nbsp;* it's not very 'hot', or the system is&lt;br&gt;
&amp;nbsp;* being overwhelmed by a lot of dirty&lt;br&gt;
&amp;nbsp;* data being delayed in the VM cache...&lt;br&gt;
&amp;nbsp;* in either event, we'll push our remaining&lt;br&gt;
&amp;nbsp;* delayed data at this point...  this will&lt;br&gt;
&amp;nbsp;* be more efficient than paging out 1 page at&lt;br&gt;
&amp;nbsp;* a time, and will also act as a throttle&lt;br&gt;
&amp;nbsp;* by delaying this client from writing any&lt;br&gt;
&amp;nbsp;* more data until all his delayed data has&lt;br&gt;
&amp;nbsp;* at least been queued to the uderlying driver.&lt;br&gt;
&amp;nbsp;*/
&lt;/div&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OSX" rel="tag"&gt;OSX&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112233268812834998?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112233268812834998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112233268812834998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233268812834998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233268812834998'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/xnu-vm.html' title='XNU VM'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112233243610991454</id><published>2005-07-25T22:57:00.000Z</published><updated>2005-07-25T23:01:51.286Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>BSD VM scanner</title><content type='html'>&lt;p&gt;
BSD vm analyzes object reference counter in page scanner:
&lt;/p&gt;
&lt;div class="code-title"&gt;vm/vm_pageout.c:vm_pageout_scan()&lt;/div&gt;
&lt;div class="code"&gt;
/*&lt;br&gt;
&amp;nbsp;* If the object is not being used, we ignore previous &lt;br&gt;
&amp;nbsp;* references.&lt;br&gt;
&amp;nbsp;*/&lt;br&gt;
if (m-&gt;object-&gt;ref_count == 0) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vm_page_flag_clear(m, PG_REFERENCED);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pmap_clear_reference(m);&lt;br&gt;
}&lt;br&gt;
....&lt;br&gt;
/*&lt;br&gt;
&amp;nbsp;* Only if an object is currently being used, do we use the&lt;br&gt;
&amp;nbsp;* page activation count stats.&lt;br&gt;
&amp;nbsp;*/&lt;br&gt;
if (actcount &amp;&amp; (m-&gt;object-&gt;ref_count != 0)) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vm_pageq_requeue(m);&lt;br&gt;
}&lt;br&gt;
....&lt;br&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/BSD" rel="tag"&gt;BSD&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112233243610991454?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112233243610991454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112233243610991454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233243610991454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233243610991454'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/bsd-vm-scanner.html' title='BSD VM scanner'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112233154441876872</id><published>2005-07-25T22:40:00.000Z</published><updated>2005-07-25T22:53:27.796Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Concurrency Control and Recovery in Database Systems</title><content type='html'>&lt;h3&gt;&lt;a href="http://research.microsoft.com/pubs/ccontrol/"&gt;Concurrency Control and Recovery in Database Systems&lt;/a&gt; by Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman.&lt;/h3&gt;

&lt;p&gt;
Delayed commit as an alternative to keeping &amp;#8222;commit-time&amp;#8220; locks: when
transaction T1 is accessing a resource modified by active transaction T2, it
just proceeds hoping that T2 will commit. If T1 tries to commit while T2 is
still active, its commit is delayed until T2 commits or aborts. If T2 aborts,
T1 has to abort too (and can be restarted). One can imagine "abort-rate"
tracked for each resource, and delayed commits are used only if it is low
enough.
&lt;/p&gt;
&lt;blockquote&gt;
        Pragmatically, this means that read locks can be released when the
        transaction terminates (i.e., when the scheduler receives the
        transaction's Commit or Abort), but write locks must be held until
        after the transaction commits or aborts (i.e., after the DM processes
        the transaction's Commit or Abort).
&lt;/blockquote&gt;
&lt;p&gt;
This strategy (&amp;#8222;Static 2PL scheduler&amp;#8220;) generates strict histories. How it
generalizes to other types of locks?
&lt;/p&gt;&lt;p&gt;
Interesting section on thrashing:
&lt;ul&gt;
 &lt;li&gt;pure restart policy (abort transaction when it tries to acquire already
   held lock) works well when data contention is high.

 &lt;/li&gt;&lt;li&gt;a measure of thrashing:

&lt;div class="mathout"&gt;W = k * k * N / D,&lt;/div&gt;
where

   &lt;span class="math"&gt;N&lt;/span&gt; - multiprogramming level,&lt;br&gt;

   &lt;span class="math"&gt;k&lt;/span&gt; - number of locks required by transaction,&lt;br&gt;

   &lt;span class="math"&gt;D&lt;/span&gt; - number of lockable entities.&lt;br&gt;

   thrashing starts when &lt;span class="math"&gt;W &gt;= 1.5&lt;/span&gt;.&lt;br&gt;

   Can be applied to resource (memory) trashing too.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Databases" rel="tag"&gt;Databases&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Concurrency" rel="tag"&gt;Concurrency&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112233154441876872?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112233154441876872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112233154441876872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233154441876872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112233154441876872'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/concurrency-control-and-recovery-in.html' title='Concurrency Control and Recovery in Database Systems'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112221923883572813</id><published>2005-07-24T15:30:00.001Z</published><updated>2009-08-21T13:49:03.882Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>limit and evaluation</title><content type='html'>&lt;p&gt;
Let &lt;span class="math"&gt;D&lt;/span&gt; be a category with functorial limits of
functors from some category &lt;span class="math"&gt;C&lt;/span&gt;. That is, there is a
functor
&lt;div class="mathout"&gt;lim : Cat(C, D) -&gt; D.&lt;/div&gt;
&lt;/p&gt;&lt;p&gt;
For each object &lt;span class="math"&gt;x&lt;/span&gt; from &lt;span class="math"&gt;C&lt;/span&gt;,
there is a functor
&lt;div class="mathout"&gt;ev_x : Cat(C, D) -&gt; D,&lt;/div&gt;
sending functor
&lt;div class="mathout"&gt;F : C -&gt; D&lt;/div&gt;
to &lt;span class="math"&gt;F(x)&lt;/span&gt;,
and sending natural transformation
&lt;div class="mathout"&gt;r : F -&gt; G : C -&gt;D&lt;/div&gt;
to its component at
&lt;span class="math"&gt;x&lt;/span&gt; (&lt;span class="math"&gt;r_x : F(x) -&gt; G(x)&lt;/span&gt;). By
mapping &lt;span class="math"&gt;x&lt;/span&gt; to &lt;span class="math"&gt;ev_x&lt;/span&gt; and
morphism &lt;span class="math"&gt;f : x -&gt; y&lt;/span&gt; to an obvious natural
transformation from &lt;span class="math"&gt;ev_x&lt;/span&gt; to &lt;span
class="math"&gt;ev_y&lt;/span&gt; we obtain a functor
&lt;div class="mathout"&gt;EV : C -&gt; Cat(Cat(C, D), D).&lt;/div&gt;
&lt;/p&gt;&lt;p&gt;
Amusing and trivially checkable fact is that
&lt;div class="mathout"&gt;lim = Lim EV.&lt;/div&gt;
That is, limits are
&lt;i&gt;always&lt;/i&gt; point-wise.
&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Mathematics" rel="tag"&gt;Mathematics&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112221923883572813?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112221923883572813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112221923883572813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112221923883572813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112221923883572813'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/limit-and-evaluation.html' title='limit and evaluation'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111271206506421822</id><published>2005-07-24T04:35:00.000Z</published><updated>2005-07-25T15:01:24.050Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>working set is not relevant</title><content type='html'>&lt;div class="kernel"&gt;
&lt;p&gt;&lt;b&gt;[&lt;/b&gt;Updated: 2005.07.24&lt;b&gt;]&lt;/b&gt;
&lt;p&gt;
The key point of working set algorithm is not &amp;#8222;&lt;span style="font-style:italic;"&gt;virtual time&lt;/span&gt;&amp;#8220; relative to which recently used pages are defined. Virtual time is a problem rather than a solution. At the time when working set algorithm was designed, there was one to one mapping between address spaces and threads. In such setup virtual time based scanning ties memory scheduling and processor scheduling and, hence, avoids thrashing, which is a situation when one resource (processor) is scheduled to achieve its maximal utilization, ignoring constraints imposed by other resource (memory) (See Dijkstra papers &lt;a href="http://www.cs.utexas.edu/users/EWD/ewd04xx/EWD408.PDF"&gt;EWD408&lt;/a&gt; and &lt;a href="http://www.cs.utexas.edu/users/EWD/ewd04xx/EWD462.PDF"&gt;EWD462&lt;/a&gt; for as always lucid an explanation).
&lt;/p&gt;&lt;p&gt;
In modern systems there is no such one to one mapping anymore. There are multiple threads executing within the same address space. There are memory consumers that are not readily identifiable with any execution context at all: file system cache (which is merged with VM in any self-respecting kernel), general in-kernel memory allocator, etc. It means that:
&lt;/p&gt;&lt;p&gt;
&lt;ul&gt;
 &lt;li&gt;there is no relevant notion of virtual time to be used during scanning;&lt;/li&gt;
 &lt;li&gt;working set control fails to bind memory and processor scheduling together,
 which will decrease its effectiveness.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
One extreme case is to consider whole system as one entity. Then
virtual time degenerates into physical one, and working set algorithm
into active/inactive queue.
&lt;/p&gt;&lt;p&gt;
Moreover, working set is not &lt;i&gt;page&lt;/i&gt; replacement algorithms at all. That is, it doesn't answer to the question &amp;#8222;System is low on memory, what page should be reclaimed?&amp;#8220; Instead it vaguely points to some address space and proposes to reclaim some unknown page from it. This made sense for the time-shared server running large number of tasks with disjoint address spaces, but for the modern system working set algorithm will be most likely finger-pointing to the Mozilla (or OpenOffice, or...) on the client and Apache (or Oracle, or...) on the server. Which is completely useless, because we still don't know &lt;i&gt;what&lt;/i&gt; page is to be reclaimed.
&lt;/p&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OS" rel="tag"&gt;OS&lt;/a&gt;-&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111271206506421822?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111271206506421822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111271206506421822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111271206506421822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111271206506421822'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/working-set-is-not-relevant.html' title='working set is not relevant'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-112214542875108405</id><published>2005-07-23T19:03:00.000Z</published><updated>2005-07-25T15:03:27.106Z</updated><title type='text'>Travel to the land of Juyed Awk Yacc</title><content type='html'>&lt;h3&gt;Travel to the land of Juyed Awk Yacc&lt;/h3&gt;

&lt;p&gt;
   &lt;a href="http://nethack.org"&gt;Nethack&lt;/a&gt; is a single-user role
   playing, dungeon exploring game. This is probably most complex RPG ever
   built. Nethack consists of a core game engine (however no such term
   existed at the time of game creation), and a number of front-ends
   (&lt;i&gt;windowing systems&lt;/i&gt;) providing a view into the game
   world. Although many GUI-based front-ends for nethack were written over
   time, original &lt;tt&gt;TTY&lt;/tt&gt;-based one is still the best: difference
   between graphic and text-based games is like difference between watching
   TV and reading a book. In the latter case it's completely up to the
   reader to create and maintain &lt;i&gt;the world&lt;/i&gt; in its imagination. As a
   result reader/player feels much greater attachment to the constructed
   reality, and is emotionally bound to it.
&lt;/p&gt;
&lt;p&gt;
   Another crucial difference between nethack and other RPG games is what
   can be termed its &lt;i&gt;orthogonality&lt;/i&gt;: nethack objects (monsters,
   tools, magic items, dungeon elements, weaponry and armor, etc.) can be
   used in a ways and combinations well beyond any fixed &amp;#8222;game script&amp;#8220;. For
   example, magic ring can be wield as a weapon, or thrown like a
   projectile, or when player polymorphs into type of monster that has no
   hands, weapon fell to the floor (and if player happens to levitate over
   water at that moment, fallen objects sink). This orthogonality if often
   referred to as &amp;#8222;&lt;a href="http://en.wikipedia.org/wiki/Nethack"&gt;Dev Team
   thought about everything&lt;/a&gt;&amp;#8220;. This makes nethack similar to the real
   world where there are laws rather than scripts.
&lt;/p&gt;
&lt;p&gt;
   Below is an account of my last (yet uncompleted) nethack game as
   &lt;tt&gt;nikita-Wiz-hum-neu-mal&lt;/tt&gt;.
&lt;/p&gt;
&lt;h4&gt;The Beginning&lt;/h4&gt;
&lt;p&gt;
   I got rather standard initial abilities, but initial inventory contained
   two extremely valuable items: a ring of invisibility and a ring of slow
   digestion. The latter is very useful in the early stages of the game,
   where starvation if one of the commonest causes of death.
&lt;/p&gt;
&lt;p&gt;
   By falling through two trapdoors I quickly descended deep into the
   dungeon. This is usually a fatal experience, but luckily, while trying
   to climb back to the safer levels, I got a wish by drinking from a
   fountain. It would be silly to waste it to anything less than the best
   armor in the game:
&lt;/p&gt;
&lt;!-- bits from other game --&gt;
&lt;!--img src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-11.jpg"--&gt;
&lt;!--img src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-11-gauntlets-of-power-from-own-ghost.jpg"--&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-wish.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-wish.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   With the ring of invisibility and the dragon scale mail I was
   well-prepared to go forward.
&lt;/p&gt;
&lt;h4&gt;&lt;a href="http://www.spod-central.org/~psmith/nh/gazetteer/mines.html"&gt;The Gnomish Mines&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;
   Even with the ring of slow digestion, exploring the Gnomish Mines is
   reasonable first step, as there is plenty of food there. Also, I hoped
   to get a luck stone and a bag of holding there.
&lt;/p&gt;
&lt;p&gt;
   Our dungeon happened to have rather rare form of &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/minetown.html"&gt;Minetown&lt;/a&gt;
   (&amp;#8222;&lt;i&gt;Grotto Town&lt;/i&gt;&amp;#8220;):
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-gnome-mall-rare.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-gnome-mall-rare.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Unfortunately there was no bag of holding anywhere, which turned to be
   constant annoyance: I was short on inventory space all the time and had
   to create multiple intermediate storage spots.
&lt;/p&gt;
&lt;p&gt;
   At the &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/minesend.html"&gt;Mines
   End&lt;/a&gt; (The Mimic of the Mines), there was a box with &lt;a
   href="http://www.lassp.cornell.edu/ardlouis/dissipative/Schrcat.html"&gt;Schroedinger's
   Cat&lt;/a&gt; inside:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-Schroedinger's-Cat.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-Schroedinger's-Cat.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;p&gt;
   I wonder what statistics an ensemble of all nethack cats follows?
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-Schroedinger's-Cat-2.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-12-Schroedinger's-Cat-2.jpg"&gt;&lt;/a&gt;
&lt;h4&gt;Sokoban&lt;/h4&gt;
&lt;p&gt;
   At the dlvl 10 there was a stairway up leading to the &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/sokoban.html"&gt;Sokoban&lt;/a&gt;
   branch of the dungeon. This branch extends upward, so the level numbers
   decrease. As passing this maze is one of the most tedious parts of the
   same, I took numerous shots, to record required sequence of moves:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-15-Vlad-Tower-sokoban.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-15-Vlad-Tower-sokoban.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-17:11:25.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-17:11:25.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-22:12:54.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-22:12:54.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-22:37:57.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-22:37:57.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-23:17:41.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-23:17:41.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-23:19:49.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-16-23:19:49.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-19-16:58:35.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-19-16:58:35.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:15:11.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:15:11.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:16:08.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:16:08.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:17:44.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:17:44.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:23:20.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:23:20.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:58:01.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-13:58:01.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-14:02:14.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-14:02:14.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-14:13:03.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-14:13:03.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   After returning from the sokoban, I descended through several ordinary
   levels...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-16:51:00.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-16:51:00.jpg"&gt;&lt;/a&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-17:15:47.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-17:15:47.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   ... before reaching &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/rogue.html"&gt;Rogue
   level&lt;/a&gt; at dlvl 15:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-18:08:27.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-18:08:27.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   There was Kenneth Arnold's ghost there with the usual funny stuff:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-18:11:00.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-18:11:00.jpg"&gt;&lt;/a&gt;
&lt;h4&gt;Quest&lt;/h4&gt;
&lt;p&gt;
   Magic portal to the &lt;a href="http://www.spod-central.org/~psmith/nh/gazetteer/quest/wiz.html"&gt;Quest&lt;/a&gt; home level was on the rogue level...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:04:01.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:04:01.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   ... but after cleaning quest home up, I decided to first descend a bit
   more through the main dungeon first:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:32:57.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:32:57.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:36:54.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-21-23:36:54.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Then I returned to the quest...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:12:03.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:12:03.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   And reached the Dark One's lore, where I found a wand of wishing:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:56:02.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:56:02.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   I wished for the ring of teleport control, because I had intrinsic
   teleport by that time.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:56:38.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:56:38.jpg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:59:09.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:59:09.jpg"&gt;&lt;/a&gt;

&lt;p&gt;
   The Dark One proved to be not that much of a challenge, albeit full of
   amusing curses:
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:31:27.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:31:27.jpg"&gt;&lt;/a&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:20:17.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-19:20:17.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   While immune to the magical attacks, he could do nothing against the old
   trusty potion of paralysis....
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-20:23:17.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-20:23:17.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   By returning by quest artefact (&lt;i&gt;the Eye of the Aethiopica&lt;/i&gt;) to the
   Neferet the Gree, I completed the quest, and...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-20:34:40.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-20:34:40.jpg"&gt;&lt;/a&gt;
&lt;h4&gt;Medusa's Island and the Castle&lt;/h4&gt;
&lt;p&gt;
   ... went downward through the main dungeon, to &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/medusa.html"&gt;
   Medusa's Island&lt;/a&gt;.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-21:57:21.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-23-21:57:21.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   I spent a &lt;i&gt;*lot*&lt;/i&gt; of time on this level, first because there was a
   couple of &lt;a
   href="http://www.cim.mcgill.ca/~simra/nhtohtml/html/demilich.html"&gt;demiliches&lt;/a&gt;
   that were busy creating monsters, but mainly because few groups of
   giants appeared there and I decided that I won't lose any opportunity to
   improve my strength (strength is improved by eating giants). There are
   few tricks there: first giant corpse is too heavy to be carried away to
   the safe place, which means that monster is better to be killed in a
   place where it can be eaten safely without its cogeni attacking you all
   the time. Second, after eating a giant corpse one has to wait a long
   time to digest it. This is where ring of hunger would be very
   useful. Welladay, I don't have one.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-01:33:09.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-01:33:09.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-01:34:24.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-01:34:24.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Nikita, meet Jabberwocky. Jabberwocky, meet Nikita.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-02:30:27.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-02:30:27.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-22:41:35.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-25-22:41:35.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   After clearing Medusa's Island somewhat I went to &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/castle.html"&gt;the
   Castle&lt;/a&gt;. As I had a ring of levitation, there was no need to muck
   with the drawbridge.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-02:31:06.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-02:31:06.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   The Castle always has a wand of wishing.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:03:13.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:03:13.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   As I am strong enough already, gauntlets of dexterity are reasonable
   choice.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:05:08.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:05:08.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Now I have standard ascension kit.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:06:39.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-26-03:06:39.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Back to the Medusa's Island.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:27:39.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:27:39.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Watch gremlins fun...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:35:28.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:35:28.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:35:39.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:35:39.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:36:12.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:36:12.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:46:50.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-01:46:50.jpg"&gt;&lt;/a&gt;
&lt;h4&gt;Gehennom&lt;/h4&gt;
&lt;p&gt;
   And through the Castle, down to the &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/valley.html"&gt;Valley
   of the Dead&lt;/a&gt;, first level of the &lt;a href="http://www.spod-central.org/~psmith/nh/gazetteer/gehennom.html"&gt;Gehennom&lt;/a&gt;
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-02:55:51.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-02:55:51.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Lot of ghosts here...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:10:39.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:10:39.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:10:53.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:10:53.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:11:52.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:11:52.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:21:38.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:21:38.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Gee... even my owns.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:22:07.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-03:22:07.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-22:50:46.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-28-22:50:46.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Below the Valley of the Dead are few normal Gehennom style mazes,
   followed by &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/juiblex.html"&gt;Juiblex'
   Swamp&lt;/a&gt;, where we find another Schroedinger's Cat... this time alive!
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-29-23:57:18.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-29-23:57:18.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-29-23:56:54.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-29-23:56:54.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Got a glimpse at my attributes...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-30-21:35:58.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-06-30-21:35:58.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Now to the &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/asmodeus.html"&gt;Asmodeus'
   Lair&lt;/a&gt;
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-01:18:47.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-01:18:47.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Oops... got a hit from the &lt;a
   href="http://www.cim.mcgill.ca/~simra/nhtohtml/html/green_slime.html"&gt;green
   slime&lt;/a&gt;.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-16:18:43.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-16:18:43.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Time to resort to the extreme measures.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-16:19:01.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-16:19:01.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Aha, Wizard of Yendor is sitting in his &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/wizard.html"&gt;tower&lt;/a&gt;. Wait
   for me, I am coming.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:00:53.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:00:53.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Entering the &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/wizard.html"&gt;Vlad's
   Tower&lt;/a&gt;
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:29:04.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:29:04.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Passing through it upward...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:36:56.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:36:56.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:40:41.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:40:41.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Killing Vlad The Impaler...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:50:48.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-17:50:48.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   And returning back to cozy Gehennom.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-18:17:58.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-18:17:58.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Peaceful mind flyer: a rare sight.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-21:46:54.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-21:46:54.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Attacked by a shade...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-23:06:26.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-23:06:26.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   and by a wraith.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-23:22:00.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-02-23:22:00.jpg"&gt;&lt;/a&gt;
&lt;h4&gt;Wizard&lt;/h4&gt;
&lt;p&gt;
   Now I can enter Wizard's Tower.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:47:20.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:47:20.jpg"&gt;&lt;/a&gt;

&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:56:22.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:56:22.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Ascending through it...
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:58:07.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-00:58:07.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Only to find out that Wizard of Yendor is little more than a vulgar thief.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-01:18:11.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-01:18:11.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   Killed him. For the first time. There will be more to come, I know.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-01:20:43.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-01:20:43.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   &lt;a
   href="http://www.spod-central.org/~psmith/nh/gazetteer/orcus.html"&gt;Orcus-Town&lt;/a&gt;.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-23:39:35.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-23:39:35.jpg"&gt;&lt;/a&gt;
&lt;p&gt;
   See? Wizard of Yendor resurrected and attacked me here. Little did he
   know how handy nearby cockatrice can be. &lt;i&gt;Attack of the clones&lt;/i&gt;.
&lt;/p&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-22:05:46.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-22:05:46.jpg"&gt;&lt;/a&gt;
&lt;a href="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-22:05:39.jpg"&gt;&lt;img border=0 width=100% src="http://linuxhacker.ru/~nikita/misc/nethack/nikita-Wiz-hum-neu-mal.2005-07-03-22:05:39.jpg"&gt;&lt;/a&gt;
&lt;h3&gt;To Be Continued&lt;/h3&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Nethack" rel="tag"&gt;Nethack&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-112214542875108405?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/112214542875108405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=112214542875108405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112214542875108405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/112214542875108405'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/07/travel-to-land-of-juyed-awk-yacc.html' title='Travel to the land of Juyed Awk Yacc'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111978323065494961</id><published>2005-06-26T09:20:00.000Z</published><updated>2005-07-23T19:10:00.526Z</updated><title type='text'>you have a strange forbidding feeling...</title><content type='html'>&lt;p&gt;
A scary thing happened to me: my first thought, while looking at
&lt;/p&gt;
&lt;div class="code-title"&gt;linux-2.6.5-7.151/lib/vsprintf.c&lt;/div&gt;
&lt;div class="code"&gt;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*fmt == 'Z' || *fmt == 'z') {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;qualifier = *fmt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fmt++;&lt;br&gt;
}&lt;br&gt;
&lt;/div&gt;
&lt;p&gt;
was something like &lt;q&gt;&lt;i&gt;Hmm... I should be careful about that &lt;a href="http://www.cim.mcgill.ca/~simra/nhtohtml/html/master_lich.html"&gt;master lich&lt;/a&gt; here...&lt;/i&gt;&lt;/q&gt;. I should throttle down.
&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Hacking" rel="tag"&gt;Hacking&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Nethack" rel="tag"&gt;Nethack&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111978323065494961?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111978323065494961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111978323065494961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111978323065494961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111978323065494961'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/06/you-have-strange-forbidding-feeling.html' title='you have a strange forbidding feeling...'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111849364747650230</id><published>2005-06-11T12:18:00.000Z</published><updated>2005-07-25T15:05:17.096Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>kernel patches for 2.6.12-rc6</title><content type='html'>&lt;div class="kernel"&gt;
&lt;p&gt;
   After long delay I updated my kernel patches to 2.6.12-rc6. This required installing &lt;a href="http://kernel.org/git/"&gt;git&lt;/a&gt; and &lt;a href="http://lwn.net/Articles/133938/"&gt;cogito&lt;/a&gt;, but it turned out that time wasn't wasted: these tools beat &lt;a href="http://bitmover.com"&gt;bitkeeper&lt;/a&gt; hands down CPU-wise.
 &lt;/p&gt;&lt;p&gt;
   New version of patches is uploaded &lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11"&gt;here&lt;/a&gt;.
 &lt;/p&gt;&lt;p&gt;
   This series include:
 &lt;dl&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_01-zoneinfo.patch"&gt;vm_01-zoneinfo.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
  Add /proc/zoneinfo file to display information about memory
  zones. Useful to analyze VM behaviour. This was merged into -mm.
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_02-skip-writepage.patch"&gt;vm_02-skip-writepage.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Don't call -&gt;writepage from VM scanner when page is met for the first time
during scan.
&lt;/p&gt;&lt;p&gt;
New page flag PG_skipped is used for this. This flag is TestSet-ed just
before calling -&gt;writepage and is cleaned when page enters inactive
list.
&lt;/p&gt;&lt;p&gt;
One can see this as &amp;#8222;second chance&amp;#8220; algorithm for the dirty pages on the
inactive list.
&lt;/p&gt;&lt;p&gt;
BSD does the same: src/sys/vm/vm_pageout.c:vm_pageout_scan(),
PG_WINATCFLS flag.
&lt;/p&gt;&lt;p&gt;
Reason behind this is that -&gt;writepages() will perform more efficient writeout
than -&gt;writepage(). Skipping of page can be conditioned on zone-&gt;pressure.
&lt;/p&gt;&lt;p&gt;
On the other hand, avoiding -&gt;writepage() increases amount of scanning
performed by kswapd.
&lt;/p&gt;&lt;p&gt;
(Possible drawback: executable text pages are evicted earlier.)
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_03-dont-rotate-active-list.patch"&gt;vm_03-dont-rotate-active-list.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Currently, if zone is short on free pages, refill_inactive_zone() starts
moving pages from active_list to inactive_list, rotating active_list as it
goes. That is, pages from the tail of active_list are transferred to its head,
thus destroying lru ordering, exactly when we need it most --- when system is
low on free memory and page replacement has to be performed.
&lt;/p&gt;&lt;p&gt;
This patch modifies refill_inactive_zone() so that it scans active_list
without rotating it. To achieve this, special dummy page zone-&gt;scan_page
is maintained for each zone. This page marks a place in the active_list
reached during scanning.
&lt;/p&gt;&lt;p&gt;
As an additional bonus, if memory pressure is not so big as to start swapping
mapped pages (reclaim_mapped == 0 in refill_inactive_zone()), then not
referenced mapped pages can be left behind zone-&gt;scan_page instead of moving
them to the head of active_list. When reclaim_mapped mode is activated,
zone-&gt;scan_page is reset back to the tail of active_list so that these pages
can be re-scanned.
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_04-__alloc_pages-inject-failure.patch"&gt;vm_04-__alloc_pages-inject-failure.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Force artificial failures in page allocator. I used this to harden some kernel code.
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_05-page_referenced-move-dirty.patch"&gt;vm_05-page_referenced-move-dirty.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
transfer dirtiness from pte to the struct page in page_referenced(). This
makes pages dirtied through mmap &amp;#8222;visible&amp;#8220; to the file system, that can write
them out through -&gt;writepages() (otherwise pages are written from
-&gt;writepage() from tail of the inactive list).
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_06-cluster-pageout.patch"&gt;vm_06-cluster-pageout.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Implement pageout clustering at the VM level.
&lt;/p&gt;&lt;p&gt;
With this patch VM scanner calls pageout_cluster() instead of
-&gt;writepage(). pageout_cluster() tries to find a group of dirty pages around
target page, called &amp;#8222;pivot&amp;#8220; page of the cluster. If group of suitable size is
found, -&gt;writepages() is called for it, otherwise, page_cluster() falls back
to -&gt;writepage().
&lt;/p&gt;&lt;p&gt;
This is supposed to help in work-loads with significant page-out of
file-system pages from tail of the inactive list (for example, heavy dirtying
through mmap), because file system usually writes multiple pages more
efficiently. Should also be advantageous for file-systems doing delayed
allocation, as in this case they will allocate whole extents at once.
&lt;/p&gt;&lt;p&gt;
Few points:
&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt; swap-cache pages are not clustered (although they can be, but by
   page-&gt;private rather than page-&gt;index) &lt;/li&gt;

 &lt;li&gt; only kswapd do clustering, because direct reclaim path should be low
   latency.&lt;/li&gt;

 &lt;li&gt; this patch adds new fields to struct writeback_control and expects
   -&gt;writepages() to interpret them. This is needed, because pageout_cluster()
   calls -&gt;writepages() with pivot page already locked, so that -&gt;writepages()
   is allowed to only trylock other pages in the cluster.&lt;/li&gt;
&lt;/ul&gt;
   Besides, rather rough plumbing (wbc-&gt;pivot_ret field) is added to check
   whether -&gt;writepages() failed to write pivot page for any reason (in latter
   case page_cluster() falls back to -&gt;writepage()).
&lt;/p&gt;&lt;p&gt;

   Only mpage_writepages() was updated to honor these new fields, but
   all in-tree -&gt;writepages() implementations seem to call
   mpage_writepages(). (Except reiser4, of course, for which I'll send a
   (trivial) patch, if necessary).
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_07-proc-stack.patch"&gt;vm_07-proc-stack.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Export kernel backtrace in &lt;tt&gt;/proc/&amp;lt;pid&amp;gt;/task/&amp;lt;tid&amp;gt;/stack&lt;/tt&gt;. Useful when debugging
deadlocks.
&lt;/p&gt;&lt;p&gt;

This somewhat duplicates functionality of SysRq-T, but is less intrusive to
the system operation and can be used in the scripts.
&lt;/p&gt;&lt;p&gt;

Exporting kernel stack of a thread is probably unsound security-wise. Use with
care.
&lt;/p&gt;&lt;p&gt;

Instead of adding yet another architecture specific function to output thread
stack through seq_file API, it introduces &amp;#8222;iterator&amp;#8220;
&lt;/p&gt;&lt;pre&gt;

void do_with_stack(struct task_struct *tsk, 
     int (*actor)(int, void *, void *, void *), void *opaque)
&lt;/pre&gt;&lt;p&gt;

that has to be implemented by each architecture, so that generic code can
iterate over stack frames in architecture-independent way.
&lt;/p&gt;&lt;p&gt;

lib/do_with_stack.c is provided for archituctures that don't implement their
own. It is based on __builtin_{frame,return}_address().
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_08-proc-sleep.patch"&gt;vm_08-proc-sleep.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
export per-process blocking statistics in &lt;tt&gt;/proc/&amp;lt;pid&amp;gt;/task/&amp;lt;tid&amp;gt;/sleep&lt;/tt&gt; and global sleeping statistics in &lt;tt&gt;/proc/sleep&lt;/tt&gt;. Statistics
collection for given file is activated on the first read of
corresponding &lt;tt&gt;/proc&lt;/tt&gt; file. When statistics collection is on on each context switch
current back-trace is built (through __builtin_return_address()). For each
monitored process there is a LRU list of such back-traces. Useful when trying
to understand where elapsed time is spent.
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_09-ll_merge_requests_fn-cleanup.patch"&gt;vm_09-ll_merge_requests_fn-cleanup.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
ll_merge_requests_fn() assigns total_{phys,hw}_segments twice. Fix this
and a typo. Merged into -mm.
&lt;/p&gt;
   &lt;/dt&gt;
   &lt;dd&gt;&lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11/vm_0a-deadline-iosched.c-cleanup.patch"&gt;vm_0a-deadline-iosched.c-cleanup.patch&lt;/a&gt;&lt;/tt&gt;&lt;/dd&gt;
   &lt;dt&gt;
&lt;p&gt;
Small cleanup.
&lt;/p&gt;
   &lt;/dt&gt;
 &lt;/dl&gt;
  &lt;/p&gt;&lt;p&gt;
   &lt;tt&gt;rmap-cleanup.patch&lt;/tt&gt; and &lt;tt&gt;WRITEPAGE_ACTIVATE-doc-fix.patch&lt;/tt&gt; were merged into Linus tree.
 &lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Hacking" rel="tag"&gt;Hacking&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel"  rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111849364747650230?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://linuxhacker.ru/~nikita/patches/2.6.12-rc6/2005.06.11' title='kernel patches for 2.6.12-rc6'/><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111849364747650230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111849364747650230' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111849364747650230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111849364747650230'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/06/kernel-patches-for-2612-rc6.html' title='kernel patches for 2.6.12-rc6'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111823637688190912</id><published>2005-06-08T12:51:00.000Z</published><updated>2005-06-08T13:17:05.433Z</updated><title type='text'>names</title><content type='html'>&lt;div class="epigraph"&gt;
&lt;p&gt;
     If you do not know the names, the knowledge of things will be lost, too.
&lt;/p&gt;&lt;p&gt;
     Carolus Linnaeus
&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111823637688190912?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111823637688190912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111823637688190912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111823637688190912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111823637688190912'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/06/names.html' title='names'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111709557330355974</id><published>2005-05-26T08:16:00.000Z</published><updated>2005-07-25T15:06:00.553Z</updated><title type='text'>Если бы я знал, что такое электричество...</title><content type='html'>&lt;p&gt;(Posted at &lt;a href="http://www.livejournal.com/community/borisborisovich/96495.html"&gt;Борис Борисович™&lt;/a&gt; LJ community)
&lt;/p&gt;&lt;p&gt;
Одним душным предгрозовым вечером 24-го мая Борис Борисович™ прогуливался по Капотне. Наскучив разглядыванием индустриальных пейзажей, он решительно направился к белевшему в сумраке зданию, позади которого проглядывали электрического вида конструкции. Сотрудники подстанции выглядели озабоченными и внимания на Бориса Борисовича™ не обращали. Лишь один из них, страшно возбуждённый, спросил: &amp;#8222;Кто клал этот кабель?!&amp;#8220;. &amp;#8222;Я не знаю&amp;#8220; --- пожал плечами Борис Борисович™ и, пройдя дальше, очутился в коротком, тускло освещенном тупичке. На дальней стене виднелся пыльный рубильник, рядом надпись: &amp;#8222;Проверено. Гаврилов, 1964.&amp;#8220;. Положив на рубильник руку, и ощутив холод металла, Борис Борисович™ прошептал: &amp;#8222;Если бы я знал, что такое электричество...&amp;#8220;, решительно дернул вниз, развернулся на левом каблуке, сделал шаг и вышел на улицу.
&lt;/p&gt;&lt;p&gt;
Порывшись в карманах он нашёл телефон, поморщил лоб, вспоминая номер и, не обращая внимания на раздавшийся позади шум, набрал: 2-12-85-06. Телефон молчал.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111709557330355974?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111709557330355974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111709557330355974' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111709557330355974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111709557330355974'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/05/blog-post.html' title='Если бы я знал, что такое электричество...'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111685171894474816</id><published>2005-05-23T12:28:00.000Z</published><updated>2005-07-25T15:06:22.943Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>SuSE owns YOU.</title><content type='html'>SuSE Yast2 online update (YOU) is a disaster. Yesterday, after downloading more than hundred megabytes of updates from SuSE FTP site, it &amp;#8222;updated&amp;#8220; kernel and NVidia dirvers so that they stopped working together. It also silently changed /etc/X11/XF86Config, corrupted /etc/dictd.conf, and installed a bunch of libraries with wrong permissions. It took me about 4 hours to fix all that.
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111685171894474816?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111685171894474816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111685171894474816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111685171894474816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111685171894474816'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/05/suse-owns-you.html' title='SuSE owns YOU.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111419221045825213</id><published>2005-04-22T17:41:00.000Z</published><updated>2005-07-23T11:12:18.690Z</updated><title type='text'>The Cook, The Thief, His Wife and Her Lover go to the masses.</title><content type='html'>&lt;a href="http://tv.rambler.ru/event.html?id=1716391"&gt;Yesterday&lt;/a&gt;, Russian nation-wide TV Channel Россия, broadcast Peter Greenway's &lt;i&gt;&lt;a href="http://petergreenaway.co.uk/ctwl.htm"&gt;The Cook, The Thief, His Wife and Her Lover&lt;/a&gt;&lt;/i&gt;. Isn't there is something very Greenwayish in the image of 40 million people turning their TV sets on to relax after a hard day only to be confronted with what can be only viewed, but not described?
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Cinema" rel="tag"&gt;Cinema&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111419221045825213?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111419221045825213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111419221045825213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111419221045825213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111419221045825213'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/cook-thief-his-wife-and-her-lover-go.html' title='The Cook, The Thief, His Wife and Her Lover go to the masses.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111375543890248081</id><published>2005-04-17T16:19:00.000Z</published><updated>2005-07-23T11:12:43.603Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>S. MacLane dies</title><content type='html'>&lt;div class="mourning"&gt;
&lt;center&gt;
&lt;a href="http://en.wikipedia.org/wiki/Mac_Lane"&gt;Saunders MacLane&lt;/a&gt; passed away on the morning of April 14. 
&lt;/center&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Mathematics" rel="tag"&gt;Mathematics&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111375543890248081?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111375543890248081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111375543890248081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111375543890248081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111375543890248081'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/s-maclane-dies.html' title='S. MacLane dies'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111333249386403946</id><published>2005-04-12T18:58:00.000Z</published><updated>2005-07-23T11:13:15.426Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>gcc error message</title><content type='html'>&lt;p&gt;
Quite some time ago (in the previous century), gcc greeted me with the following self-explanatory &lt;a href="http://linuxhacker.ru/~nikita/misc/funny-gcc-error-message"&gt;message&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
My feelings toward C++ only increased since then.
&lt;/p&gt;&lt;p&gt;
[Corrected 2005.06.08 to include message by reference and avoid damaging layout.]
&lt;/p&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/C++" rel="tag"&gt;C++&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111333249386403946?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111333249386403946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111333249386403946' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111333249386403946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111333249386403946'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/gcc-error-message.html' title='gcc error message'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111330237502817635</id><published>2005-04-12T10:31:00.000Z</published><updated>2005-07-25T15:06:59.020Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Inaccessible Cardinals</title><content type='html'>&lt;center&gt;
 &amp;#8222;&lt;b&gt;On the Consistency of Choice for Strongly Inaccessible Cardinals&lt;/b&gt;&amp;#8220;.&lt;br&gt;
&lt;/center&gt;
&lt;center&gt;
 &amp;#8222;&lt;b&gt;О непротиворечивости выбора сильно недостижимых кардиналов&lt;/b&gt;&amp;#8220;.&lt;br&gt;
&lt;/center&gt;
In this from &lt;a href="http://cnn.com/2005/WORLD/europe/04/09/pope.main/index.html"&gt;CNN&lt;/a&gt; or from &lt;i&gt;Seminaire Bourbaki Novembre 1974 56`eme annee&lt;/i&gt;?
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Mathematics" rel="tag"&gt;Mathematics&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Pope" rel="tag"&gt;Pope&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111330237502817635?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111330237502817635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111330237502817635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111330237502817635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111330237502817635'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/inaccessible-cardinals.html' title='Inaccessible Cardinals'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111324200192793734</id><published>2005-04-11T17:32:00.000Z</published><updated>2005-07-25T15:08:13.023Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>purelisp: object types</title><content type='html'>As was noted in the previous &lt;a href="http://nikitadanilov.blogspot.com/2005/04/purelisp-introduction.html"&gt;post&lt;/a&gt;, objects in purelisp are partitioned into disjoint types.
&lt;h3&gt;types of objects&lt;/h3&gt;
&lt;p&gt;
Some LISP object types have &lt;i&gt;read syntax&lt;/i&gt;, which is a way to generate string representation of a given object. Built-in function &lt;tt&gt;(read)&lt;/tt&gt; builds object given its string representation. Read syntax is given together with description of object types below.
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Number&lt;/b&gt;. Represent arbitrary range integers (implemented in local.purelisp.eval.LInt by java.math.BigInteger). Number evaluates to itself, cannot be applied to anything, supports basic arithmetic operations.
&lt;/p&gt;
&lt;div class="code-title"&gt;read syntax for integers&lt;/div&gt;
&lt;div class="code"&gt;
10&lt;br&gt;
0o12&lt;br&gt;
0xa&lt;br&gt;
0t1010&lt;br&gt;
&lt;/div&gt;
all represent number 10
&lt;p&gt;
&lt;b&gt;String&lt;/b&gt;. Evaluates to itself, cannot be applied. Implemented on top of java.lang.String.
&lt;/p&gt;&lt;p&gt;
&lt;b&gt;Environment&lt;/b&gt;. Environment is used to evaluate objects of type &lt;i&gt;symbol&lt;/i&gt;. Specifically, each environment contains &lt;i&gt;bindings&lt;/i&gt; from symbols to objects. Binding can be thought of as a pair &lt;tt&gt;(s, o)&lt;/tt&gt;, where &lt;tt&gt;s&lt;/tt&gt; is a symbol, and &lt;tt&gt;o&lt;/tt&gt; is an object &lt;tt&gt;s&lt;/tt&gt; is bound to. Environment, therefore, is a partial function from symbols to objects. New bindings can be installed and value symbol is bound to can be changed.
&lt;/p&gt;&lt;p&gt;
Environments are arranged into tree-like hierarchy: each environment (except the root of the tree) has parent environment, and if symbol binding is not found in the environment, search is repeated in the parent recursively. Environment is said to extend its parent. At the top of the tree is &lt;i&gt;global environment&lt;/i&gt; that contains bindings for standard LISP symbols. Interactive interpreter maintains its own environment where user adds new or modifies existing symbol bindings. There is second environment hierarchy, not affected by LAMBDA evaluation, used to implement traditional LISP dynamic scoping, but it is not current used in the language. Dynamic parent environment can be accessed through &lt;tt&gt;(env-dynamic env)&lt;/tt&gt; built-in function.
&lt;/p&gt;&lt;p&gt;
During computation there always is so-called current environment. Initially it is environment of interactive interpreter, later it can be replaced when applying LAMBDA functions (see below) or evaluating &lt;tt&gt;(eval-in env o)&lt;/tt&gt; built-in function (see below). Evaluation is always performed in the current environment, and, therefore, there is no need to explicitly mention evaluation environment.
&lt;/p&gt;&lt;p&gt;
Environments have no read syntax.
&lt;/p&gt;&lt;p&gt;
&lt;b&gt;Symbol&lt;/b&gt;. Symbol is a LISP object with unique name. Name is the only identity and state that symbol has. Symbols are used to point to other objects. It has to be stressed that while superficially similar to variables in other languages, symbols are quite different:
&lt;ul&gt;
  &lt;li&gt;symbol has &lt;b&gt;NO&lt;/b&gt; value attached to it. It can be used as a key to look up value in environment, but in different environments it can have different values.&lt;/li&gt;
  &lt;li&gt;symbol is first-class object itself: it can be stored in data-structures including environments (so that value of symbol can be another symbol).&lt;/li&gt;
&lt;/ul&gt;
Symbols cannot be applied and their evaluation was described above (see &lt;b&gt;Environment&lt;/b&gt;).
&lt;/p&gt;&lt;p&gt;
Read syntax for a symbol is just its name. If unknown yet valid identifier is read, new symbol is created.
&lt;/p&gt;&lt;p&gt;
Symbols, integers, and strings are collectively known as &lt;i&gt;atoms&lt;/i&gt;.
&lt;/p&gt;&lt;p&gt;
&lt;b&gt;Cons cell&lt;/b&gt;. Cons cell is a pair of references to other LISP objects. First and seconds references are idiosyncratically known as &lt;tt&gt;CAR&lt;/tt&gt; and &lt;tt&gt;CDR&lt;/tt&gt;, and are accessed through &lt;tt&gt;(car c)&lt;/tt&gt; and &lt;tt&gt;(cdr c)&lt;/tt&gt; built-in functions respectively. Cons cells are used to build linked lists: CAR of the first cell in a list points to the first object in the list, CDR point to the second cell in the list, whose CAR points to the second object in the list, and CDR points to... List it terminated by the pointer to NIL (see below).
&lt;/p&gt;&lt;p&gt;
Obviously, much more general possibly cyclic data-structures, can be built from cons cells. We shall call NIL terminated lists described above &lt;i&gt;well-formed lists&lt;/i&gt;. If list is terminated by reference to an object that is neither cons cell nor NIL, it will be called &lt;i&gt;dotted list&lt;/i&gt;, otherwise data-structure rooted at the cons cell is called &lt;i&gt;improper list&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;
&lt;div class="code-title"&gt;read syntax for well-formed lists&lt;/div&gt;
&lt;div class="code"&gt;
(1 2 3)&lt;br&gt;
(1 (1 2 "foo") "bar")&lt;br&gt;
&lt;/div&gt;
&lt;div class="code-title"&gt;read syntax for dotted lists&lt;/div&gt;
&lt;div class="code"&gt;
(1 2 . 3)&lt;br&gt;
&lt;/div&gt;
Note that dotted list notation can be used to represent any cons cell whose CAR and CDR have read syntax: &lt;tt&gt;(A . B)&lt;/tt&gt; builds cons cell with A as CAR, and B as CDR.
&lt;/p&gt;&lt;p&gt;
Cons cell cannot be applied, and has peculiar and very important evaluation rule. To evaluate cons cell following is done in order:
&lt;ul&gt;
   &lt;li&gt;if CDR of cell it not well-formed list, abort evaluation;&lt;/li&gt;
   &lt;li&gt;cell's CAR is evaluated, let's call resulting object F;&lt;/li&gt;
   &lt;li&gt;create copy of CDR list, &lt;i&gt;i.e.&lt;/i&gt;, create new well-formed list containing pointers to the same objects and in the same order as CDR of cell being evaluated. Call first cons cell of resulting list A0;&lt;/li&gt;
   &lt;li&gt;if F is built-in function or LAMBDA function, evaluate all objects in A0 and create a list of evaluation results called A1. Otherwise let A1 be A0;&lt;/li&gt;
   &lt;li&gt;apply F to A1.&lt;/li&gt;
&lt;/ul&gt;
This obviously accounts for neither concurrency nor re-entrancy issues (&lt;i&gt;i.e.&lt;/i&gt;, structure of argument list could change while evaluated, either as result of said evaluation, or due to some concurrent activity).
&lt;/p&gt;&lt;p&gt;
Basically, to evaluate well-formed list, its CAR is evaluated and applied to the remaining elements of list as arguments. Arguments are evaluated if CAR evaluates to function (either built-in or LAMBDA), and are not evaluated otherwise (which leaves us with CAR evaluating to special form).
&lt;/p&gt;&lt;p&gt;
&lt;b&gt;NIL&lt;/b&gt;. NIL is a special object the denotes empty list. It is used to define well-formed lists above. NIL object is bound to symbol "nil" in the global environment. Cannot be applied, evaluates to itself. As a special exception, built-in functions &lt;tt&gt;(car)&lt;/tt&gt; and &lt;tt&gt;(cdr)&lt;/tt&gt; can be applied to NIL and return NIL in this case.
&lt;/p&gt;
&lt;div class="code-title"&gt;read syntax for NIL&lt;/div&gt;
&lt;div class="code"&gt;
nil
&lt;/div&gt;
&lt;p&gt;
&lt;b&gt;LAMBDA&lt;/b&gt;. LAMBDA a is LISP object (special form) used to create lambda-functions. First, the notion of lambda-form is needed. Lambda form is a cons cell at which following well-formed list is rooted:
&lt;/p&gt;
&lt;div class="code-title"&gt;LAMBDA form&lt;/div&gt;
&lt;div class="code"&gt;
(lambda (P1 ... PM) E1 ... EN)
&lt;/div&gt;
&lt;ul&gt;
    &lt;li&gt;First element of lambda form can be anything that evaluates to LAMBDA (&lt;i&gt;e.g.&lt;/i&gt;, "lambda" symbol). Note that this makes notion of lambda-form dependent on the environment in which form is evaluated.&lt;/li&gt;
    &lt;li&gt;Second element of lambda-form is well-formed list called &lt;i&gt;list of parameters&lt;/i&gt;. Elements of this list are called &lt;i&gt;parameters&lt;/i&gt;. In traditional LISP, parameters have to be symbols. Purelisp has some extension (to be described later.) Parameters list may be empty.&lt;/li&gt;
    &lt;li&gt;Remaining elements of lambda-form are said to constitute its &lt;i&gt;body&lt;/i&gt;. Body may be empty.
&lt;/ul&gt;
&lt;div class="code-title"&gt;LAMBDA form examples&lt;/div&gt;
&lt;div class="code"&gt;
(lambda (x y) y)&lt;br&gt;
(lambda (f) ((lambda (x) (f (x x))) (lambda (y) (f (y y)))))&lt;br&gt;
(lambda nil 3)&lt;br&gt;
&lt;/div&gt;
&lt;p&gt;
Lambda-form is not treated in any special way by the interpreter. Instead its evaluation is done as for any cons cell (see above), and results in application of LAMBDA to the list &lt;tt&gt;((P1 ... PM) E1 ... EN)&lt;/tt&gt;. As LAMBDA is special form, elements of this list are not evaluated. Result of this application is new LISP object: lambda-function.
&lt;/p&gt;&lt;p&gt;
&lt;b&gt;Lambda-function&lt;/b&gt;. Lambda-function can be thought as a pair &lt;tt&gt;(ENV, ((P1 ... PM) E1 ... EN))&lt;/tt&gt;, where &lt;tt&gt;env&lt;/tt&gt; is an environment in which lambda-form was evaluated. Lambda-function evaluates to itself. Its importance stems from its application rule. To apply lambda-function &lt;tt&gt;(ENV, ((P1 ... PM) E1 ... EN))&lt;/tt&gt; to the list of arguments (A1 ... AK) do the following:
&lt;ul&gt;
    &lt;li&gt;if K != M abort application;&lt;/li&gt;
    &lt;li&gt;create new environment ELOCAL extending ENV;&lt;/li&gt;
    &lt;li&gt;for each i: 1 &lt;= i &lt;= M, bind Pi to Ai in ELOCAL;&lt;/li&gt;
    &lt;li&gt;for each i: 1 &lt;= i &lt;= N, evaluate Ei in ELOCAL;&lt;/li&gt;
    &lt;li&gt;result of application is the result of EN evaluation, or NIL if body is empty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Again, this doesn't account for pathological cases where structure of lambda-form recorded in lambda-function changes during evaluation.
&lt;/p&gt;&lt;p&gt;
As one can see lambda-functions allow programmer to construct objects with arbitrary application rules, and, therefore (through lists of the form &lt;tt&gt;(lambda-function A1 ... AM)&lt;/tt&gt;), objects with arbitrary evaluation rules. Lambda-functions are main computation-structuring mechanism in LISP.
&lt;/p&gt;
[in next installation: what makes purelisp different?]
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/LISP" rel="tag"&gt;LISP&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111324200192793734?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://nikitadanilov.blogspot.com/2005/04/purelisp-introduction.html' title='purelisp: object types'/><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111324200192793734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111324200192793734' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111324200192793734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111324200192793734'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/purelisp-object-types.html' title='purelisp: object types'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111324067483402752</id><published>2005-04-11T16:45:00.000Z</published><updated>2005-07-25T15:08:35.243Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>purelisp: introduction</title><content type='html'>&lt;p&gt;
Some time ago (I just re-checked and... Good Lord it was in October of 2003, time moves fast indeed) I wrote simple LISP interpreter (&lt;a href="http://nikita.w3.to/code/purelisp/applet.html"&gt;purelisp&lt;/a&gt;) in Java. This, otherwise seemingly pointless activity could be justified as an exercise in &lt;a href="http://www.sablecc.org/"&gt;SableCC&lt;/a&gt; usage.
&lt;/p&gt;
&lt;h3&gt;SableCC&lt;/h3&gt;
&lt;p&gt;
SableCC is a nice compiler building toolkit with pretty standard (by nowaday standards) set of features: on input it takes a description of the language, and produces Java classes with lexer and skeleton parser. Language is defined by a grammar and terminals are defined by regular expressions. Our simple version of LISP uses &lt;a href="http://nikita.w3.to/code/purelisp/lisp-grammar.c"&gt;lisp.grammar&lt;/a&gt; as the definition, note that larger fraction of language definition is a table indicating what unicode characters are "&lt;i&gt;letters&lt;/i&gt;" in the sense of being acceptable as part of an identifier.
&lt;/p&gt;&lt;p&gt;
From language definition SableCC generates:
&lt;ul&gt;
    &lt;li&gt;Java classes corresponding to tokens of the grammar.&lt;/li&gt;
    &lt;li&gt;Lexer class that transforms input stream into sequence of tokens (optionally omitting some tokens, &lt;i&gt;e.g.&lt;/i&gt;, white-spaces).&lt;/li&gt;
    &lt;li&gt;Parser class that constructs typed AST (abstract syntax tree) from the sequence of tokens.&lt;/li&gt;
    &lt;li&gt;Set of &lt;i&gt;tree-walker&lt;/i&gt; base classes. Tree-walkers traverse tree in specific order, calling certain methods of tree node object when entering and leaving it. This is called "&lt;i&gt;visitor pattern&lt;/i&gt;" by the people in dire need of names.&lt;/li&gt;
&lt;/ul&gt;

The only thing left to do to finish simple interpreter is to subclass suitable tree-walker with the class that interprets program while traversing its AST. LISP program (as LISP fans will never cease to remind us) is but a LISP data, hence, natural choice for our interpreter is to build LISP object as a result of tree traversal. And building such an object is indeed simple: &lt;a href="http://www.geocities.com/nikitadanilov/code/purelisp/TreeBuilder.java"&gt;local.purelisp.eval.TreeBuilder&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;purelisp introduction&lt;/h3&gt;
&lt;p&gt;
Computational universe of purelisp consists of objects, partitioned into disjoint &lt;i&gt;types&lt;/i&gt;. Objects can be &lt;i&gt;evaluated&lt;/i&gt;. Evaluation takes as input an object to be evaluated and auxiliary object of type &lt;i&gt;environment&lt;/i&gt; that affects evaluation. Result of evaluation is an object again. This can be the same object that is being evaluated, some already existing object, or new object. Ultimately, evaluation can result in error, and no result is produced in this case. Rules of evaluation for some objects are hard-wired into interpreter. For other objects, evaluation is multi-step process defined in terms of some actions performed on other objects.
&lt;/p&gt;&lt;p&gt;
In particular, one important type of objects, viz. &lt;i&gt;cons cells&lt;/i&gt; have evaluation defined in terms of &lt;i&gt;application&lt;/i&gt; of an object to a sequence of objects (referred to as &lt;i&gt;arguments&lt;/i&gt; of application). Rules of application are again type-dependent: hard-wired into interpreter (&lt;i&gt;e.g.&lt;/i&gt; for built-in functions), or defined through combination of evaluation and application.
&lt;/p&gt;&lt;p&gt;
Evaluation and application are fundamental mutually-recursive operations on top of which computation is implemented in LISP.
&lt;/p&gt;&lt;p&gt;
LISP program is actually nothing more than description of object according to some standard syntax. LISP interpreter reads this description, build corresponding objects and evaluates it in some "&lt;i&gt;current&lt;/i&gt;" environment.
&lt;/p&gt;
[in next installation: object types in purelisp.]
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/LISP" rel="tag"&gt;LISP&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111324067483402752?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://nikita.w3.to/code/purelisp/applet.html' title='purelisp: introduction'/><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111324067483402752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111324067483402752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111324067483402752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111324067483402752'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/purelisp-introduction.html' title='purelisp: introduction'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111271253924119253</id><published>2005-04-05T14:45:00.000Z</published><updated>2005-07-23T11:15:24.870Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>page tickets</title><content type='html'>&lt;div class="kernel"&gt;
MACH VM had (or still has if Mac OS X counts) an interesting detail in its VM scanner implementation:
&lt;div class="code-title"&gt;osfmk/vm/vm_page.h&lt;/div&gt;
&lt;div class="code"&gt;
/* &lt;br&gt;
&amp;nbsp;* Each page entered on the inactive queue obtains a ticket from a&lt;br&gt;
&amp;nbsp;* particular ticket roll.  Pages granted tickets from a particular &lt;br&gt;
&amp;nbsp;* roll  generally flow through the queue as a group.  In this way when a&lt;br&gt;
&amp;nbsp;* page with a ticket from a particular roll is pulled from the top of the&lt;br&gt;
&amp;nbsp;* queue it is extremely likely that the pages near the top will have tickets&lt;br&gt;
&amp;nbsp;* from the same or adjacent rolls.  In this way the proximity to the top&lt;br&gt;
&amp;nbsp;* of the queue can be loosely ascertained by determining the identity of&lt;br&gt;
&amp;nbsp;* the roll the pages ticket came from. &lt;br&gt;
&amp;nbsp;*/&lt;br&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OS" rel="tag"&gt;OS&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111271253924119253?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111271253924119253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111271253924119253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111271253924119253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111271253924119253'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/04/page-tickets.html' title='page tickets'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111226605311370507</id><published>2005-03-31T10:31:00.000Z</published><updated>2005-07-25T15:12:19.513Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>the power of gdb</title><content type='html'>Yesterday I was running long file system stress test (&lt;a href="http://www.codemonkey.org.uk/cruft/fsx-linux.c"&gt;fsx&lt;/a&gt; if you want to know) when X server on my workstation locked up completely (because it ran on a heavily patched kernel as turned out later). One consequence of this was that xterm which fsx output was going to, went, together with X server, to the land of Eternal GoodDrawable and stopped caring about silly clients sending frantic write(2)s to it.
&lt;br&gt;
&lt;br&gt;
fsx stopped which was unfortunate. So I logged to the test box and did
&lt;div class="code-title"&gt;Session&lt;/div&gt;
&lt;div class="code"&gt;
$ gdb fsx $(pgrep fsx) # attach to the fsx&lt;br&gt;
(gdb) bt&lt;br&gt;
#0  0x90010760 in write ()&lt;br&gt;
#1  0x90026104 in _swrite ()&lt;br&gt;
#2  0x90020c80 in __sflush ()&lt;br&gt;
#3  0x90031e00 in __fflush ()&lt;br&gt;
#4  0x90006e4c in __sfvwrite ()&lt;br&gt;
#5  0x90006ef0 in __sprint ()&lt;br&gt;
#6  0x90006a48 in __vfprintf ()&lt;br&gt;
#7  0x9000c76c in vfprintf ()&lt;br&gt;
#8  0x000025a0 in prt ()&lt;br&gt;
#9  0x00004a0c in dotruncate ()&lt;br&gt;
#10 0x000051c0 in test ()&lt;br&gt;
#11 0x0000659c in main ()&lt;br&gt;
#12 0x0000220c in _start (argc=2, argv=0xbffffa14, envp=0xbffffa20) at /SourceCache/Csu/Csu-46/crt.c:267&lt;br&gt;
#13 0x00002080 in start ()&lt;br&gt;
(gdb) # yes it really stuck doing write to the stdout. And yes, this is Mac OS X.&lt;br&gt;
(gdb) # now fun part begins&lt;br&gt;
(gdb) call (int)close(1) # close standard output&lt;br&gt;
$1 = 0&lt;br&gt;
(gdb) # it worked! Leave fsx in piece...&lt;br&gt;
(gdb) detach&lt;br&gt;
(gdb) quit&lt;br&gt;
&lt;/div&gt;
and test was running further happily. 
&lt;br&gt;
The moral: gdb can save your day.
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Hacking" rel="tag"&gt;Hacking&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OSX" rel="tag"&gt;OSX&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111226605311370507?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111226605311370507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111226605311370507' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111226605311370507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111226605311370507'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/03/power-of-gdb.html' title='the power of gdb'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-111170102246344044</id><published>2005-03-24T20:27:00.001Z</published><updated>2008-10-04T18:27:00.053Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>RSX</title><content type='html'>&lt;div class="kernel"&gt;
[expanded. 2004.03.25]&lt;br&gt;
Lately, I looked through sources of RSX &lt;i&gt;executive&lt;/i&gt; at &lt;a href="http://www.bitsavers.org"&gt;bitsavers.org&lt;/a&gt;. RSX (which stands for &lt;b&gt;R&lt;/b&gt;ealtime &lt;b&gt;S&lt;/b&gt;ystem e&lt;b&gt;X&lt;/b&gt;ecutive or &lt;b&gt;R&lt;/b&gt;esource &lt;b&gt;S&lt;/b&gt;haring e&lt;b&gt;X&lt;/b&gt;ecitive) is a collective name for the series of operating systems &lt;tt&gt;DEC&lt;/tt&gt; developed for its &lt;tt&gt;PDP&lt;/tt&gt; processors.
Initial version was RSX-15 developed for PDP-15 processor (a member of 18b family of DEC processors---poorer and ultimately abandoned cousins of another branch that got us PDP-11) by Sam Reese, &lt;a href="http://www.demillar.com/RSX/"&gt;Dan Brevik&lt;/a&gt;, Hank Krejci and Bernard LaCroute. See: &lt;a href="http://groups-beta.google.com/group/comp.os.vms/msg/51870e4fc2d88da5?output=gplain"&gt;a bit of history&lt;/a&gt;, &lt;a href="http://www.demillar.com/RSX/RSXdocument.pdf"&gt;original design&lt;/a&gt;, official DEC &lt;a href="http://www.bitsavers.org/pdf/dec/pdp15/DEC-15-GRQA-D_RSX15_1971.pdf"&gt;reference manual&lt;/a&gt;.

Later on, RSX was ported to PDP-11 (yes, version numbers can very well go down), resulting in succession of RSX-11A, RSX-11B, RSX-11C, and RSX-11D, the latter being full-blown operating system, multi-user and multi-tasking. You think it's quite an achievement for a platform with 32K bytes of primary storage? Obviously David Cutler wasn't impressed, as he re-wrote it from scratch to consume less resources giving birth to RSX-11M (and later to VAX VMS, and Windows NT).

Unfortunately, no RSX-11 kernel sources seem available (neither A-D, nor M and beyond versions), except for little witty pieces &lt;a href="http://article.gmane.org/gmane.os.netbsd.ports.vax/1479"&gt;here&lt;/a&gt; and &lt;a href="http://www.omlettesoft.com/listquotes.php3?index=394"&gt;there&lt;/a&gt; (bitsavers, however sports &lt;a href="http://www.bitsavers.org/pdf/dec/pdp11/rsx11/OS_internalsCourse_1983/"&gt;materials&lt;/a&gt; from DEC's classes on RSX-11 internals).

XVM/RSX-15 sources are available at bitsavers:

&lt;ul&gt;
    &lt;li&gt;Executive proper: &lt;a href="http://www.bitsavers.org/bits/DEC/pdp15/dectape/XVM_RSX/_textfiles/DEC-XV-IXRAA-A-UA4_02-28-77/RSX.P1_160.txt"&gt;P1&lt;/a&gt; and &lt;a href="http://www.bitsavers.org/bits/DEC/pdp15/dectape/XVM_RSX/_textfiles/DEC-XV-IXRAA-A-UC1_02-28-77/RSX.P2_161.txt"&gt;P2&lt;/a&gt;, and&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://www.bitsavers.org/bits/DEC/pdp15/dectape/XVM_RSX/_textfiles/DEC-XV-IXRAA-A-UA5_02-28-77/"&gt;MCR&lt;/a&gt; (Monitor Console Routine)&lt;/li&gt;
&lt;/ul&gt;

Why would one waste time looking through the obscure non-portable kernel that
ran on a hardware decommissioned quarter of century ago? A lot of reasons:

&lt;ul&gt;
    &lt;li&gt;It is radically different from UNIX, which is, basically, the only
    publicly available kernel source base to-day.
    &lt;/li&gt;&lt;li&gt;It was written at the times when computing was still young and
    engineers didn't take a lot of things for granted, so one can see how and
    why they come to their designs.
    &lt;/li&gt;&lt;li&gt;It's rather small by nowadays standards and easy to understand.
    &lt;/li&gt;&lt;li&gt;It has surprisingly good comments.
    &lt;/li&gt;&lt;li&gt;It was one of the first and probably (for quite a long time) largest open-source projects: hundreds of megabytes of software for RSX were available in the source form (&lt;a href="http://www.trailing-edge.com/~shoppa/freewareFAQ.html"&gt;DECUS tapes&lt;/a&gt;)
    &lt;/li&gt;&lt;li&gt;I agree with the sentiments R. Pike, &lt;i&gt;esq.&lt;/i&gt; expressed in &lt;a href="http://www.cs.bell-labs.com/who/rob/utah2000.pdf"&gt;Systems Software Research is Irrelevant&lt;/a&gt; article (also see Rik van Riel's &lt;a href="http://surriel.com/research_wanted/"&gt;note&lt;/a&gt;): modern operating system research revolves around (or, rather, inside of) a cluster of well-known old ideas. By looking at the roots of operating system development, one sees that these ideas are but &lt;i&gt;choices&lt;/i&gt;.
    &lt;/li&gt;&lt;li&gt;Nostalgia, of course. At the end of 80s I worked on some PDP &lt;a href="http://www.village.org/pdp-11/faq"&gt;clones&lt;/a&gt;: Электроника-100/25, СМ-4.
    &lt;/li&gt;
&lt;/ul&gt;

&lt;br&gt;
At the center of RSX-15 is its executive, also known as monitor or kernel. This is small program written in PDP-15 assembly language, that maintains following abstractions:

&lt;dl&gt;
  &lt;dt&gt;memory partitioning
  &lt;dd&gt;rudimentary memory management scheme. Memory is partitioned during system generation into &lt;i&gt;partitions&lt;/i&gt; and &lt;i&gt;common blocks&lt;/i&gt;.
  &lt;dt&gt;task and scheduling.
  &lt;dd&gt;Task is a machine code that can be executed under control of executive. Task is &lt;i&gt;installed&lt;/i&gt; when it is known to the executive (specifically, registered in STL---global System Task List). Tasks are created by &lt;i&gt;task builder&lt;/i&gt;---special task that builds task by linking relocatable code with libraries and storing task on disk in the same format it will be stored in the primary storage (i.e., task loading is just copying it from disk to the core, which is important for &lt;i&gt;real-time&lt;/i&gt; operating system). Some tasks are resident, which means they are always in core. Installed task may be requested for execution (placed into ATL---Active Task List), and get its share of processor cycles subject to priority and memory constraints. Simple fixed priority scheme is used. Memory is managed on partition granularity: each task has a partition assigned to it during build, and will be loaded into core when said partition is free. Partition can be used for one task only.
  &lt;dt&gt;interrupt management
  &lt;dd&gt;executive itself handles clock interrupt only. All other interrupts are handled by special IO Handler Tasks (IOHTs), any installed task may become IOHT by &lt;i&gt;connecting&lt;/i&gt; to interrupt line.
  &lt;dt&gt;device management.
  &lt;dd&gt;list of physical devices and mapping between physical and logical units (LUNs). Per-device prioritized IO queues. Asynchronous IO as a default mechanism. LUNs are global.
  &lt;dt&gt;interface to space management for disks
  &lt;dd&gt;bitmap of free blocks. Implemented by IO handler task, not executive.
  &lt;dt&gt;interface to simple flat file system.
  &lt;dd&gt;Implemented by IO handler task.
&lt;/dl&gt;

&lt;br&gt;
&lt;b&gt;[...To be continued...]&lt;/b&gt;
&lt;br&gt;

Here are some interesting features:

&lt;ul&gt;
    &lt;li&gt;usage of API (Automatic Priority Interrupts) to implement concurrency
   control.&lt;p&gt;In RSX-11M this was replaced with FORK processing: interrupts never directly access kernel tables, hence, no synchronization is required on the uniprocessor. Similar to soft interrupts.&lt;/p&gt;&lt;/li&gt;
   &lt;li&gt;separation of STL (system task list) and ATL (active task list)---a form of two level scheduling: long level scheduling decisions are made by installing task into STL, and assigning resources (devices and core partitions) to it. Short term scheduling is done by scanning ATL which is sorted by task priority.&lt;/li&gt;
   &lt;li&gt;interrupt is viewed (and used) more like asynchronous goto, rather than asynchronous procedure call. For example, there is a procedure that scans ATL (active task list, sorted by task priority). Interrupt may add task to the ATL, and so scan has to be restarted if interrupt happens during it. To achieve this, interrupt handlers do a jump to the address stored in L6TV ("Level Six Transfer Vector"). When normal task runs, L6TV points to the routine that saves registers in the task's "core partition". When ATL scan is started, L6TV is modified to point to the ATL scan procedure itself. As a result, if interrupt happens, scan will be restarted automatically. Note, that interrupt handlers do _not_ save registers in the stack (they do not create stack frame).&lt;/li&gt;
   &lt;li&gt;"pseudo partitions" that overlay IO memory used to control devices from
   non-privileged tasks.&lt;/li&gt;
   &lt;li&gt;RSX is a &lt;i&gt;radical&lt;/i&gt; micro-kernel: the only thing executive handles is processor scheduling. Everything else (including processing of interrupts other than clock) is handled by tasks. One consequence of this is that executive interface is fundamentally asynchronous: most calls take &lt;i&gt;event variable&lt;/i&gt; as an argument, and calling task may wait for call completion by doing
&lt;pre&gt;
        WAITFOR eventvar
&lt;/pre&gt;
This is impossible to do in UNIX where system calls are served on the kernel stack permanently attached to the process. In UNIX, kernel is a &lt;i&gt;library&lt;/i&gt; executing in protected mode, while RSX is a collection of autonomous tasks each running with its own stack (this architecture, of course, requires very fast context switches).&lt;/li&gt;
   &lt;li&gt;file system as special device driver layered on top of driver for underlying stable storage device: &lt;i&gt;file oriented device&lt;/i&gt;. Note, that this also unifies the notion of file and device, but... other way around.&lt;/li&gt;
   &lt;li&gt;&lt;tt&gt;SEEK&lt;/tt&gt; call is used to open particular file on a devcie. After that LUN is effectively &lt;i&gt;narrowed&lt;/i&gt; (in EMACS sense) to mean opened file.&lt;/li&gt;
   &lt;li&gt;all executables are known to the executive (listed in STL).&lt;/li&gt;
   &lt;li&gt;system image can be stored on the permanent storage (by &lt;tt&gt;SAVE&lt;/tt&gt;) and booted from (warm start), like in Smalltalk or LISP system.&lt;/li&gt;
   &lt;li&gt;instead of having separate run-queues and wait-queues, tasks are kept in single ATL. As the only synchronization mechanism available is event variable, "scheduler" simply checks whether waiting tasks can be run while scanning ATL.&lt;/li&gt;
   &lt;li&gt;tasks are so light-weight that clock queue (&lt;i&gt;callouts&lt;/i&gt; in UNIX terms) is a list of tasks rather than functions.&lt;/li&gt;
   &lt;li&gt;each task provides its own procedure to save its context on preempt&lt;/li&gt;
   &lt;li&gt;no security of any sort. Give them enough rope.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OS" rel="tag"&gt;OS&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-111170102246344044?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/111170102246344044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=111170102246344044' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111170102246344044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/111170102246344044'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2005/03/rsx.html' title='RSX'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-107219547595645019</id><published>2003-12-23T16:04:00.000Z</published><updated>2005-07-25T15:07:33.323Z</updated><title type='text'>adaptive replacement</title><content type='html'>&lt;span class="fullpost"&gt;&lt;/span&gt;
&lt;div class="kernel"&gt;
&lt;a href="http://groups.google.com/groups?hl=ru&amp;lr=&amp;amp;ie=UTF-8&amp;oe=UTF-8&amp;amp;threadm=8950%40saturn.ucsc.edu&amp;rnum=1&amp;amp;prev=/groups%3Fq%3Dvm%2Breplacement%2Bgroup:comp.os.*%26hl%3Dru%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3D8950%2540saturn.ucsc.edu%26rnum%3D1"&gt; &amp;#8222;adaptive replacement better than Working Set?&amp;#8220;&lt;/a&gt; has (an implicit) idea: VM page replacement should keep a &amp;#8222;&lt;em&gt;spectrum&lt;/em&gt;&amp;#8220; of accesses to a given page. Too high and too  low frequences should be filtered out, because they:
  &lt;ul&gt;&lt;li&gt;represent correlated references, and&lt;/li&gt;
     &lt;li&gt;irrelevant,&lt;/li&gt;
   &lt;/ul&gt;respectively
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/OS" rel="tag"&gt;OS&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-107219547595645019?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/107219547595645019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=107219547595645019' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/107219547595645019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/107219547595645019'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2003/12/adaptive-replacement.html' title='adaptive replacement'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry></feed>
