<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8870493191508591473</atom:id><lastBuildDate>Fri, 24 Jul 2026 06:06:12 +0000</lastBuildDate><category>java</category><category>задачка</category><category>paragliding</category><category>c++</category><category>photo</category><category>linux</category><category>story</category><category>qt</category><category>datastructures</category><category>парадром</category><category>hints</category><category>bash</category><category>clojure</category><category>video</category><category>javascript</category><category>map</category><category>quote</category><category>tomcat</category><category>youtube</category><category>debug</category><category>garbage</category><category>gc</category><category>gentoo</category><category>jit</category><category>mozilla</category><category>performance</category><category>spring</category><category>webkit</category><category>куракин</category><category>реклама</category><category>eclipse</category><category>games</category><category>gflogger</category><category>imagemagick</category><category>intellij</category><category>java10</category><category>kotlin</category><category>kotlin-intellij-plugin</category><category>photosight.ru</category><category>postgresql</category><category>python</category><category>web</category><category>wiki</category><category>wine</category><category>alsa</category><category>android</category><category>artwork</category><category>blogger</category><category>code style</category><category>css</category><category>dns</category><category>erlang</category><category>flex</category><category>fp</category><category>gimp</category><category>graal</category><category>graph</category><category>gtk+</category><category>hazelcast</category><category>hosting git mercurial</category><category>jabber</category><category>jni</category><category>linkage</category><category>log4j</category><category>network</category><category>photoshop</category><category>picasa</category><category>power</category><category>regexp</category><category>security</category><category>sip</category><category>skype</category><category>sql</category><category>testing</category><category>time</category><category>unsafe</category><category>webdav</category><category>windows</category><category>yourmart</category><category>Неми</category><category>дети</category><category>игрушки</category><category>карта</category><category>комиск</category><category>новости</category><category>ноутбуки</category><category>пикник</category><category>смешарики</category><category>социальная реклама</category><category>экология</category><category>яндекс</category><title>Крылья, ноги... Хвост!</title><description></description><link>http://dolzhenko.blogspot.com/</link><managingEditor>noreply@blogger.com (Vladimir Dolzhenko)</managingEditor><generator>Blogger</generator><openSearch:totalResults>213</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6211477856164176685</guid><pubDate>Mon, 19 Jul 2021 04:57:00 +0000</pubDate><atom:updated>2021-07-19T07:57:39.658+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">intellij</category><category domain="http://www.blogger.com/atom/ns#">kotlin</category><category domain="http://www.blogger.com/atom/ns#">kotlin-intellij-plugin</category><title>IntelliJ Kotlin plugin internals: On-the-flight diagnostics reporting</title><description>&lt;h2&gt;Background&lt;/h2&gt;
Highlighting of a Kotlin file prior to Kotlin 1.5 (and Kotlin IntelliJ plugins based on Kotlin before 1.5) in oversimplified way was sequential:
&lt;ul&gt;&lt;li&gt;run a compiler for a kotlin file&lt;/li&gt;&lt;li&gt;collects diagnostics (i.e. errors and warnings) for each PSI element&lt;/li&gt;&lt;li&gt;highlight them in a file&lt;/li&gt;&lt;/ul&gt;

&lt;h2&gt;Goal&lt;/h2&gt;
Provide feedback on compilation errors (or warning) as soon as possible.

&lt;br/&gt;
&lt;h2&gt;Impl, details and trade-offs&lt;/h2&gt;

The biggest concern in a provided highlighting process:&lt;br/&gt;&lt;br/&gt;&lt;b&gt;why we have to wait till the end of kotlin file analysis to show errors and warnings&lt;/b&gt;? &lt;br/&gt;&lt;br/&gt;

If you ever compile some file in a console using &lt;code&gt;gcc&lt;/code&gt; or &lt;code&gt;javac&lt;/code&gt; directly (w/o &lt;code&gt;make&lt;/code&gt; or any other build managers), you definitely recall that compilers print diagnostic messages during compilation while entire compilation process for a single file could takes some seconds more.&lt;br/&gt;&lt;br/&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;
That&#39;s the general idea behind the improvement covered by &lt;a href=&quot;https://youtrack.jetbrains.com/issue/KT-37702&quot;&gt;KT-37702: Code analysis speed: on-the-fly analysis diagnostics reporting&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;.

There were some obstacles to implement this feature:
&lt;ul&gt;&lt;li&gt;No callback from front-end of compiler to report diagnostics&lt;/li&gt;&lt;li&gt;Quick fixes. Many quick fix action use the type of expression in their descriptions, to provide the type we have to analyse expression that reported diagnostic during resolve.&lt;br/&gt;In short: it&#39;s a recursion.&lt;/li&gt;&lt;li&gt;Diagnostics could be suppressed by &lt;code&gt;@Suppress(&quot;DIAGNTOSTIC_NAME&quot;)&lt;/code&gt;.&lt;br/&gt;Same problem with recursion as we need resolve the type of &lt;code&gt;@Suppress&lt;/code&gt;. Sure some heuristics could be used but it can&#39;t cover general case.&lt;/li&gt;&lt;/ul&gt;

&lt;br/&gt;How these problems were addressed ?&lt;br/&gt;
&lt;ul&gt;&lt;li&gt;To add a callback we have to step into front-end of compiler.&lt;ul&gt;&lt;li&gt;Compilers (in the classic theory of compilers) are splitted into two parts: front-end and back-end.&lt;/li&gt;&lt;li&gt;In short: back-end generates a target code (binary/byte/bit code) from a properly built and resolved AST.&lt;/li&gt;&lt;li&gt;Front-end has to perform type inference (e.g. to specify type for value &lt;code&gt;q&lt;/code&gt; in expression &lt;code&gt;val q = 41 + 1&lt;/code&gt;), check AST with ControlFlowAnalysis (e.g. there is a return point from non-void function), DataFlowAnalysis etc.&lt;br/&gt;In short: namely &lt;b&gt;Front-End&lt;/b&gt; reports all diagnostics from a compiler and would not go futher to Back-end if there is something completely wrong like broken compilation.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Quick-fixes could be calculated at the end of entire resolve. I think it is a reasonable trade-off: user gets faster feedback as red or yellow underlined code while all extra functionality stays the same as it was before.&lt;br/&gt;&lt;/li&gt;
&lt;li&gt;A bit ironic approach to address &lt;code&gt;@Suppress&lt;/code&gt; problem: in this case diagnostics reported to the suppressed block are shown after the end of resolve. So, if you suppress anything for entire file - you are switching off on-the-flight diagnostic reporting.&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;

&lt;h2&gt;Demo&lt;/h2&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.blogger.com/video.g?token=AD6v5dxVhTB-3Q3cn6MmHnlrzjUaZ6j72PaYYLUVKQoMUokZuf3ogjff-j9cUGQDanv66_EmD47R56tMBLrxArYr4w&#39; class=&#39;b-hbp-video b-uploaded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;br/&gt;On-the-flight diagnostics reporting in action.&lt;/div&gt;
&lt;br/&gt;

&lt;h2&gt;Annotator vs HighlightVisitor&lt;/h2&gt;
To highlight a file &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/e04256a833e62196bcdfe2cfa51981a10d5a8b2f/platform/analysis-api/src/com/intellij/lang/annotation/Annotator.java&quot;&gt;&lt;code&gt;Annotator&lt;/code&gt;&lt;/a&gt; extension point was used:
&lt;pre class=&quot;java&quot;&gt;
&lt;code&gt;
public interface Annotator {
  void annotate(@NotNull PsiElement element, 
      @NotNull AnnotationHolder holder);
}
&lt;/code&gt;
&lt;/pre&gt;

&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/16efea745d7a2976b61371f38693e6992358ffd9/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java&quot;&gt;&lt;code&gt;GeneralHighlightingPass&lt;/code&gt;&lt;/a&gt; invokes suitable &lt;code&gt;Annotator&lt;/code&gt;s for a file. As well it defines an order of PSI elements of a file to highlight for &lt;code&gt;Annotator&lt;/code&gt;s. E.g. it starts with actually visible PSI elements.&lt;br/&gt;
&lt;br/&gt;

So, it does not work well with on-the-flight diagnostics reporting as compiler reports diagnostics in completely different order than &lt;code&gt;GeneralHighlightingPass&lt;/code&gt; does.&lt;br/&gt;&lt;br/&gt;

I.e. &lt;code&gt;Annotator&lt;/code&gt; is not suitable for our goal. But &lt;code&gt;GeneralHighlightingPass&lt;/code&gt; works with another type of extension point &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/0e2aa4030ee763c9b0c828f0b5119f4cdcc66f35/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightVisitor.java&quot;&gt;&lt;code&gt;HighlightVisitor&lt;/code&gt;&lt;/a&gt;:
&lt;pre class=&quot;java&quot;&gt;
&lt;code&gt;
public interface HighlightVisitor {

  boolean suitableForFile(@NotNull PsiFile file);

  void visit(@NotNull PsiElement element);

  boolean analyze(@NotNull PsiFile file,
     boolean updateWholeFile, 
     @NotNull HighlightInfoHolder holder,
     @NotNull Runnable action);

}&lt;/code&gt;
&lt;/pre&gt;
&lt;br/&gt;
That suits for us quite well. Implementing &lt;code&gt;HighlightVisitor#analyze&lt;/code&gt; we are free to highlight a &lt;code&gt;file&lt;/code&gt; in any order:&lt;br/&gt; highlight PSI elements those are reported on-the-fly and all left-overs like suppressed blocks and generate quick-fixes when resolve is ready. 
&lt;br/&gt;
&lt;br/&gt;
&lt;b&gt;Note:&lt;/b&gt; on-the-fly diagnostic reporting improves &lt;b&gt;perceptual&lt;/b&gt; performance as it reduces the latency between the change in a file (like typing) and the 1st diagnostic to be highlighted.&lt;br/&gt;

&lt;h2&gt;Surprise side effect&lt;/h2&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzoCq3vVJ3EP2aiib4qxsdIwpAGBe9aDkV8bxK1uG8A2kaZYjH31y7VyJ3olGKdvZPDsKGvzhhfGmYp6SSWadu14qstjLFKkXhYdLBHk0hxKRd931NAMAeYYdvpoDDw9VYvC_OpbqRK6s/s2474/KT-37702.png&quot; style=&quot;display: block; padding: 1em 0;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; width=&quot;320&quot; data-original-height=&quot;1356&quot; data-original-width=&quot;2474&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzoCq3vVJ3EP2aiib4qxsdIwpAGBe9aDkV8bxK1uG8A2kaZYjH31y7VyJ3olGKdvZPDsKGvzhhfGmYp6SSWadu14qstjLFKkXhYdLBHk0hxKRd931NAMAeYYdvpoDDw9VYvC_OpbqRK6s/s320/KT-37702.png&quot;/&gt;&lt;/a&gt;
Performance chart: total highlighting time of files from Kotlin project.&lt;br/&gt;
Noticeable change in the middle: on-the-fly diagnostic reporting is committed.
&lt;/div&gt;&lt;br/&gt;

The biggest side effect happened due to revision of highlighting process of Kotlin files.&lt;br/&gt;&lt;br/&gt;

Results of resolve, diagnostics and so-called &lt;code&gt;bindingContext&lt;/code&gt; (a magic map with lots of details on PSI like its inferred type etc), are intensively used by many things in a plugin: highlighting, autocompletion, inspection, intensions, quick fixes, gutter icons etc.&lt;br/&gt;Kotlin maintains its resolution cache per file via &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/db51da3b80ff9db7eb3f32664fa3d269019783c8/plugins/kotlin/analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt&quot;&gt;PerFileAnalysisCache&lt;/a&gt;. I.e. to get results of the resolve for any element we need to get a reference to &lt;code&gt;containingFile&lt;/code&gt;, or be precise &lt;code&gt;containingKtFile&lt;/code&gt;.&lt;br/&gt;&lt;br/&gt; 

So, interested highlighting process steps (before the change) are:&lt;br/&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;GeneralHighlightingPass&lt;/code&gt; runs an &lt;code&gt;Annotator&lt;/code&gt; that visit every PSI element of a file&lt;/li&gt;
  &lt;li&gt;For each PSI element &lt;code&gt;containingKtFile&lt;/code&gt; is invoked to get a resolve results from &lt;code&gt;PerFileAnalysisCache&lt;/code&gt;.&lt;ul&gt;&lt;li&gt;To get access to &lt;code&gt;containingKtFile&lt;/code&gt; we have to traverse over a tree from an PSI element to its root.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br/&gt;

&lt;code&gt;HighlightVisitor#analyze&lt;/code&gt; provides a reference to a file, therefore it is redundant to invoke &lt;code&gt;containingKtFile&lt;/code&gt; on every PSI element.&lt;br/&gt;

The effect depends on a number of PSI elements and roughly depends on a file size. That&#39;s the reason why we don&#39;t see noticeable performance boost for a small files.&lt;br/&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

On-the-fly diagnostic reporting improves:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;perceptual&lt;/b&gt; performance, reducing latency between a change in a file and actual highlighting of the 1st error or warning.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;actual&lt;/b&gt; performance of total highlighting process due to elimination of a big number of &lt;code&gt;containingKtFile&lt;/code&gt; invocations.&lt;/li&gt;
&lt;/ul&gt;</description><link>http://dolzhenko.blogspot.com/2021/07/intellij-kotlin-plugin-on-the-fly-diagnostics.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzoCq3vVJ3EP2aiib4qxsdIwpAGBe9aDkV8bxK1uG8A2kaZYjH31y7VyJ3olGKdvZPDsKGvzhhfGmYp6SSWadu14qstjLFKkXhYdLBHk0hxKRd931NAMAeYYdvpoDDw9VYvC_OpbqRK6s/s72-c/KT-37702.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-871492224391434791</guid><pubDate>Wed, 21 Apr 2021 14:26:00 +0000</pubDate><atom:updated>2021-05-02T18:40:03.216+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">intellij</category><category domain="http://www.blogger.com/atom/ns#">kotlin</category><category domain="http://www.blogger.com/atom/ns#">kotlin-intellij-plugin</category><category domain="http://www.blogger.com/atom/ns#">testing</category><title>IntelliJ Kotlin plugin internals: Run test gutter icon - The story of one small optimization</title><description>&lt;b&gt;Disclaimer&lt;/b&gt;: Hope I will fill the gaps later on in next posts.&lt;br/&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;a href=&quot;https://youtrack.jetbrains.com/issue/KTIJ-408&quot;&gt;KTIJ-408: Show &quot;run test&quot; gutter icon before semantic analysis&lt;/a&gt;&lt;br/&gt;
&lt;h2&gt;Goal&lt;/h2&gt;
to show run test gutter icons as fast as it is possible and don&#39;t wait till entire analysis is done.&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;text-align:center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ZzGtb_45EfbKGr9QcbeK-fhDZoVMFzfixgwV_W7a5UI5VD_wy4omMj0ZSKHEKIOMtcnni-WcCtMlgKjKabffuWifN-xrJI7W_dHZo75se2Zgz6v-rUQx375NtQgQOsr8CSj5vLz8yHM/s916/ktor-sessiontest-runtestguttericons.png&quot; style=&quot;display: block; padding: 1em 0; text-align: center; &quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; width=&quot;320&quot; data-original-height=&quot;422&quot; data-original-width=&quot;916&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ZzGtb_45EfbKGr9QcbeK-fhDZoVMFzfixgwV_W7a5UI5VD_wy4omMj0ZSKHEKIOMtcnni-WcCtMlgKjKabffuWifN-xrJI7W_dHZo75se2Zgz6v-rUQx375NtQgQOsr8CSj5vLz8yHM/s320/ktor-sessiontest-runtestguttericons.png&quot;/&gt;&lt;/a&gt;Run test icons are on the left side&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;
&lt;h2&gt;Background&lt;/h2&gt;
For Kotlin language (as for any other programming language) we have our own, Kotlin specific, &lt;i&gt;AST&lt;/i&gt; (Abstract Syntax Tree) representation. IntelliJ platfrom uses &lt;a href=&quot;https://plugins.jetbrains.com/docs/intellij/psi.html&quot;&gt;&lt;b&gt;PSI&lt;/b&gt; (Program Structure Interface)&lt;/a&gt; , for the sake of simplicity it could be considered as AST on steroids. Actually it works in AST-mode when you open a file in an editor.&lt;br/&gt;&lt;br/&gt;

Kotlin syntax significantly differs from Java syntax, so it should not surprise that there is a Kotlin PSI instead of Java PSI:&lt;br/&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;fun foo() = &quot;foo&quot;
&lt;/code&gt;&lt;/pre&gt;

E.g. Kotlin syntax allows to skip a return type when it could be inferred from an expression. &lt;br/&gt;&lt;br/&gt;
For Kotlin there is a &lt;code&gt;KtFile&lt;/code&gt; (that is surprise, descendant of &lt;code&gt;PsiFile&lt;/code&gt;) but &lt;code&gt;KtClass&lt;/code&gt; and &lt;code&gt;KtNamedFunction&lt;/code&gt; are not descendants of &lt;code&gt;PsiClass&lt;/code&gt; and &lt;code&gt;PsiMethod&lt;/code&gt; correspondingly.&lt;br/&gt;&lt;br/&gt;

&lt;h2&gt;Light Classes&lt;/h2&gt;
Kotlin, to look like Java in IntelliJ, uses a mimic technique known as &lt;b&gt;Light Classes&lt;/b&gt;:&lt;br/&gt;
Basic idea of LightClasses is to wrap Kotlin PSI into Java PSI. You can turn a &lt;code&gt;KtClass&lt;/code&gt; into a &lt;code&gt;PsiClass&lt;/code&gt; with &lt;code&gt;PsiMethod&lt;/code&gt;s. &lt;br/&gt;&lt;br/&gt;

The hidden elephant is in that some types have to be inferred from a code. &lt;br/&gt;&lt;br/&gt;
Like in example above: the return type of &lt;code&gt;foo()&lt;/code&gt; function is &lt;code&gt;String&lt;/code&gt;. To get it we have to perform an analysis (&lt;code&gt;resolve types&lt;/code&gt; or just simple &lt;code&gt;run resolve&lt;/code&gt;). &lt;br/&gt;&lt;br/&gt;

I.e. to build &lt;b&gt;Light Classes&lt;/b&gt; we have to have fully resolved code. &lt;br/&gt;&lt;br/&gt;

Actually, IntelliJ Kotlin plugin has a Top-Down single threaded resolution. It is quite expensive and usually it is performed during syntax highlighting with extensions used by &lt;code&gt;&lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java&quot;&gt;GeneralHighlightingPass&lt;/a&gt;&lt;/code&gt; (&lt;i&gt;Note:&lt;/i&gt; gonna describe highlighting process and highlight passes linearization more detailed). &lt;br/&gt;&lt;br/&gt;

&lt;b&gt;In short&lt;/b&gt;: GeneralHighlightingPass runs resolve (that is a single threaded). Anyone, who wants to get resolve, has to wait. When resolve is done, result of resolve is cached and reused by all other requesters like &lt;b&gt;Light Class&lt;/b&gt; builder. &lt;br/&gt;&lt;br/&gt;

To rephrase:  &lt;br/&gt;
you cannot get LightClasses earlier than resolve i.e. syntax highlighting. &lt;br/&gt;&lt;i&gt;Note: to be honest you get a lazy LightClass but in a general case to iterate over all methods or super types it relies on resolve.&lt;/i&gt;&lt;br/&gt;&lt;br/&gt;

&lt;h2&gt;Run test gutter icons&lt;/h2&gt;

To show &lt;b&gt;run test gutter icons&lt;/b&gt; (e.g. for JUnit4) IntelliJ Java plugin uses &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/0e2aa4030ee763c9b0c828f0b5119f4cdcc66f35/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java#L245&quot;&gt;&lt;code&gt;JUnitUtil#isJUnit4TestClass(PsiClass,boolean)&lt;/code&gt;&lt;/a&gt; (there are similar methods for JUnit3, JUnit5, TestNG etc). &lt;br/&gt;&lt;br/&gt;

Instead of reinventing the wheel IntelliJ Kotlin plugin utilize a huge and rich legacy of its Java brother.&lt;br/&gt;&lt;br/&gt;

Now, when you know some background of IntelliJ Kotlin plugin, you know why do you have quite noticeable delay between opening a file and seeing test run gutter icons: to use &lt;code&gt;JUnitUtil#isJUnit4TestClass(PsiClass,boolean)&lt;/code&gt; we have to convert Kotlin PSI into Java PSI using LightClasses that is built on top of resolve.&lt;br/&gt;&lt;br/&gt;

Let&#39;s have a look on how this &lt;a href=&quot;https://github.com/JetBrains/intellij-community/blob/0e2aa4030ee763c9b0c828f0b5119f4cdcc66f35/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java#L277&quot;&gt;method is implemented&lt;/a&gt;:

&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;for (final PsiMethod method : psiClass.getAllMethods()) {
  ProgressManager.checkCanceled();
  if (TestUtils.isExplicitlyJUnit4TestAnnotated(method) || 
    JUnitRecognizer.willBeAnnotatedAfterCompilation(method))
      return true;
}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

I.e. a class is considered as a test class if there is &lt;b&gt;at least one&lt;/b&gt; method annotated with &lt;code&gt;@org.junit.Test&lt;/code&gt;. &lt;br/&gt;&lt;br/&gt;

But, It is possible to figure out from Kotlin PSI if a class has &lt;b&gt;at least one&lt;/b&gt; &lt;s&gt;method&lt;/s&gt; function (in terms of Kotlin) annotated with &lt;code&gt;@org.junit.Test&lt;/code&gt;. &lt;br/&gt;
Well, there is &lt;i&gt;a small problem&lt;/i&gt;: usually people use &lt;code&gt;@Test&lt;/code&gt; annotation rather fully qualified name as &lt;code&gt;@org.junit.Test&lt;/code&gt; or even Kotlin alias &lt;code&gt;@kotlin.test.Test&lt;/code&gt; that points to the same.&lt;br/&gt;
It is possible to resolve fqName looking into a import list of a file. Again it is just a PSI operation.&lt;br/&gt;&lt;br/&gt;

The same approach could be applied for test &lt;s&gt;methods&lt;/s&gt; functions: if it has &lt;code&gt;@org.junit.Test&lt;/code&gt;, it has &lt;code&gt;public&lt;/code&gt; visibility etc.&lt;br/&gt;&lt;br/&gt;

Sounds great, but there are some pitfalls: e.g. what if class extends some other class that &lt;b&gt;could&lt;/b&gt; have test functions ?&lt;br/&gt;&lt;br/&gt;

Indeed, in this case this approach does not work and we have to fallback to the LightClasses solution. &lt;br/&gt;&lt;br/&gt;

Shall we fallback in all cases if we can&#39;t say is it a test class (or test function) or not ?&lt;br/&gt;&lt;br/&gt;

&lt;b&gt;No&lt;/b&gt;. There are several cases when we know that class could not be a test class (besides the case when we don&#39;t have a junit4 dependency for the module):
&lt;ul&gt;&lt;li&gt;Class does not have any super classes (except &lt;code&gt;Any&lt;/code&gt; i.e. &lt;code&gt;Object&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Data class&lt;/li&gt;
&lt;li&gt;Private class&lt;/li&gt;
&lt;li&gt;class without any public functions&lt;/li&gt;  
&lt;/ul&gt;

Run test gutter icon on Kotlin PSI in action:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;640&#39; height=&#39;500&#39; src=&#39;https://www.blogger.com/video.g?token=AD6v5dwAIxcfFbgJNOlqGSKtbvJPbK3DxRmEzUP3ow4P2xuB--ygX2LzfoxEfHMA_GUkzCxxuhlN8veDlH3fpD8NAw&#39; class=&#39;b-hbp-video b-uploaded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;br/&gt;
before change is on the left - after is on the right
&lt;/div&gt;


</description><link>http://dolzhenko.blogspot.com/2021/04/intellij-kotlin-plugin-run-test-gutter.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ZzGtb_45EfbKGr9QcbeK-fhDZoVMFzfixgwV_W7a5UI5VD_wy4omMj0ZSKHEKIOMtcnni-WcCtMlgKjKabffuWifN-xrJI7W_dHZo75se2Zgz6v-rUQx375NtQgQOsr8CSj5vLz8yHM/s72-c/ktor-sessiontest-runtestguttericons.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-5432937468235544138</guid><pubDate>Thu, 12 Apr 2018 11:03:00 +0000</pubDate><atom:updated>2018-04-12T15:15:27.114+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">graal</category><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">java10</category><title>Guava, Graal and Partial Escape Analysis</title><description>Recently &lt;a href=&quot;https://twitter.com/mreinhold/status/976125756584615937&quot;&gt;java 10 release&lt;/a&gt; happened - in fact, &lt;b&gt;Graal&lt;/b&gt; was available earlier, but now it is more easy to access and use it - &lt;a href=&quot;https://twitter.com/shelajev/status/976177307734986753&quot;&gt;Congratulations, you&#39;re running #Graal!&lt;/a&gt; - just add a couple options:

&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler&lt;/code&gt;&lt;/pre&gt;

What does it can provide for us and what kind of enhancements we can expect to get, and more over - what dirty-hacks could be dropped ?&lt;br/&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;
Let&#39;s explore &lt;i&gt;an example&lt;/i&gt; that a bit synthetic but based on a real production code.&lt;br/&gt;

&lt;h2&gt;Guava&lt;/h2&gt;

I bet lots of you hear or even use &lt;b&gt;Preconditions&lt;/b&gt; class from &lt;b&gt;guava&lt;/b&gt; library:

&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;checkArgument(value &amp;gt; 0, &quot;Non-negative value is expected, was %s&quot;, value);&lt;/code&gt;&lt;/pre&gt;

Everything is perfect while we have not met that piece of code on a &lt;i&gt;critical execution path&lt;/i&gt; - the issue is in &lt;b&gt;implicit garbage&lt;/b&gt; production.

That&#39;s the body of &lt;code&gt;checkArgument&lt;/code&gt; method :

&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;  public static void checkArgument(
      boolean expression,
      @Nullable String errorMessageTemplate,
      @Nullable Object... errorMessageArgs) {
    if (!expression) {
      throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;
Let&#39;s turn implicit into explicit:&lt;br/&gt;&lt;br/&gt;

&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;boolean expression = value &amp;gt; 0;
Object[] errorMessageArgs = new Object[]{Integer.valueOf(value)};
if (!expression) {
  throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
}&lt;/code&gt;&lt;/pre&gt;&lt;br/&gt;

Hereby we&#39;ve got a dilemma: Usually such kind of checks in a production code are safe guards - from one side we don&#39;t want to pay (extra and unnecessary garbage) for that, from another side do not want to drop &lt;i&gt;fail fast&lt;/i&gt; checks.&lt;br/&gt;
&lt;br/&gt;
In fact the root cause of problem are in &lt;b&gt;autoboxing&lt;/b&gt; and &lt;b&gt;varargs&lt;/b&gt; objects, those could be not used at all (esp. in positive scenarios). &lt;br/&gt;
&lt;br/&gt;
Unfortunately, when &lt;a href=&quot;https://www.youtube.com/watch?v=K6c3W6vhQOA&quot;&gt;&lt;b&gt;Escape Analysis (rus.)&lt;/b&gt;&lt;/a&gt; faces the conditional branch it can &lt;b&gt;not&lt;/b&gt; determine object as unnecessary.&lt;br/&gt;
&lt;br/&gt;
Ok, how can we address this problem ? &lt;br/&gt;
&lt;br/&gt;
For instance, do method overload of &lt;code&gt;checkArgument&lt;/code&gt; (in fact it has been done in guava &lt;b&gt;&amp;gt;= 20&lt;/b&gt; for the case of 1 or 2 primitive arguments):&lt;br/&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;  public static void checkArgument(boolean expression, @Nullable String errorMessageTemplate, int p1) {
    if (!expression) {
      throw new IllegalArgumentException(format(errorMessageTemplate, p1));
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;
Well, what if there more than one or two arguments (for those there are overloaded methods in &lt;b&gt;guava&lt;/b&gt;) ? &lt;br/&gt;

The answer is - write your own hack (adding more and more overloaded methods) or experience extra garbage pressure. I faced a place in our prod code that has combination of 3 &lt;b&gt;int&lt;/b&gt;s and 1 &lt;b&gt;String&lt;/b&gt; that is executed millions of times and the response time is constrained by SLA.&lt;br/&gt;

&lt;h2&gt; Graal&lt;/h2&gt;

Now, let&#39;s have a look to &lt;b&gt;Java 10&lt;/b&gt; and &lt;code&gt;-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler&lt;/code&gt;

&lt;b&gt;Graal&lt;/b&gt; contains tones of different improvements and new type of optimizations, in particular &lt;b&gt;Partial Escape Analysis&lt;/b&gt; - one of that, in short, is in that it is &lt;i&gt;able to detect that some of object allocations are used only in one of a condition branch&lt;/i&gt; - therefore - it is legal to move that allocation from outside of branch into that particular branch where objects are used.

&lt;h2&gt; The moment of truth. JMH&lt;/h2&gt;

&lt;a href=&quot;https://gist.github.com/vladimirdolzhenko/938877e2cb309006464608cc20d1667c&quot;&gt;PartialEATest&lt;/a&gt;:

&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
@Warmup(iterations = 5, time = 5000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 5000, timeUnit = TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class PartialEATest {

    @Param(value = {&quot;-1&quot;, &quot;1&quot;})
    private int value;

    @Benchmark
    public void allocate(Blackhole bh) {
        checkArg(bh, value &amp;gt; 0, &quot;expected non-negative value: %s, %s&quot;, object, 1000, &quot;A&quot;, 700);
    }

    private static void checkArg(Blackhole bh, boolean cond, String msg, Object ... args){
        if (!cond){
            bh.consume(String.format(msg, args));
        }
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(PartialEATest.class.getSimpleName())
                .addProfiler(GCProfiler.class)
                .build();

        new Runner(opt).run();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;
Among all others we are interesting in allocations - that&#39;s why I turned &lt;b&gt;GCProfiler&lt;/b&gt; on :&lt;br/&gt;

&lt;table class=&quot;jmhResults&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Options&lt;/th&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;(value)&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Units&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-Graal&lt;/td&gt;
&lt;td&gt;PartialEATest.allocate:·gc.alloc.rate.norm&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;1008,000&lt;/td&gt;
&lt;td&gt;±   0,001&lt;/td&gt;
&lt;td&gt;B/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-Graal&lt;/td&gt;
&lt;td&gt;PartialEATest.allocate:·gc.alloc.rate.norm&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;32,000&lt;/td&gt;
&lt;td&gt;±   0,001&lt;/td&gt;
&lt;td&gt;B/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+Graal&lt;/td&gt;
&lt;td&gt;PartialEATest.allocate:·gc.alloc.rate.norm&lt;/td&gt;
&lt;td&gt;-1&lt;/td&gt;
&lt;td&gt;1024,220&lt;/td&gt;
&lt;td&gt;±   0,908&lt;/td&gt;
&lt;td&gt;B/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+Graal&lt;/td&gt;
&lt;td&gt;PartialEATest.allocate:·gc.alloc.rate.norm&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;≈ 10⁻⁴&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;B/op&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br/&gt;

It is pretty clear that &lt;b&gt;Graal&lt;/b&gt; does not allocate objects without reason. It&#39;s the right time to drop &lt;i&gt;performance dirty hacks&lt;/i&gt; like shown overloaded methods.
&lt;br/&gt;
&lt;h2&gt; Compiled method &lt;/h2&gt;
&lt;br/&gt;
To be 100% sure let&#39;s check generated assembler code we have in case of old and good &lt;b&gt;C2&lt;/b&gt; vs &lt;b&gt;Graal&lt;/b&gt; - for that we need to use &lt;b&gt;hsdis&lt;/b&gt; - download it from somewhere or [build by your own](http://dolzhenko.blogspot.com/2018/03/build-hsdis-with-java-10-on-macosx.html), and add some jvm parameters: &lt;br/&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code&gt;-XX:+UnlockDiagnosticVMOptions 
-XX:PrintAssemblyOptions=intel 
-XX:CompileCommand=print,&quot;com/elastic/PartialEATest.*&quot; &lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;
&lt;h3&gt; Compiled method :: C2&lt;/h3&gt; 
&lt;br/&gt;
There are tooones of generated code - &lt;a href=&quot;https://gist.github.com/vladimirdolzhenko/4c17b4476bbb9c98cdd51f2c6ae1572e&quot;&gt;entire C2 generated code&lt;/a&gt; - let&#39;s have a took to it up to occurrence of first &lt;i&gt;autoboxing&lt;/i&gt;:
&lt;br/&gt;
&lt;pre&gt;&lt;code&gt;ImmutableOopMap{rbx=Oop }pc offsets: 1684 1697 Compiled method (c2)     619  736       4       com.elastic.PartialEATest::allocate (55 bytes)
 total in heap  [0x00000001189a0c90,0x00000001189a1410] = 1920
 relocation     [0x00000001189a0e08,0x00000001189a0e38] = 48
 main code      [0x00000001189a0e40,0x00000001189a1060] = 544
 stub code      [0x00000001189a1060,0x00000001189a1078] = 24
 oops           [0x00000001189a1078,0x00000001189a10a0] = 40
 metadata       [0x00000001189a10a0,0x00000001189a10b0] = 16
 scopes data    [0x00000001189a10b0,0x00000001189a1210] = 352
 scopes pcs     [0x00000001189a1210,0x00000001189a13c0] = 432
 dependencies   [0x00000001189a13c0,0x00000001189a13c8] = 8
 handler table  [0x00000001189a13c8,0x00000001189a1410] = 72
----------------------------------------------------------------------
com/elastic/PartialEATest.allocate(Lorg/openjdk/jmh/infra/Blackhole;)V  [0x00000001189a0e40, 0x00000001189a1078]  568 bytes
[Entry Point]
[Constants]
  # {method} {0x000000022ea937b8} &#39;allocate&#39; &#39;(Lorg/openjdk/jmh/infra/Blackhole;)V&#39; in &#39;com/elastic/PartialEATest&#39;
  # this:     rsi:rsi   = &#39;com/elastic/PartialEATest&#39;
  # parm0:    rdx:rdx   = &#39;org/openjdk/jmh/infra/Blackhole&#39;
  #           [sp+0x30]  (sp of caller)
  0x00000001189a0e40: cmp    rax,QWORD PTR [rsi+0x8]
  0x00000001189a0e44: jne    0x0000000110eb7580  ;   {runtime_call ic_miss_stub}
  0x00000001189a0e4a: xchg   ax,ax
  0x00000001189a0e4c: nop    DWORD PTR [rax+0x0]
[Verified Entry Point]
  0x00000001189a0e50: mov    DWORD PTR [rsp-0x14000],eax
  0x00000001189a0e57: push   rbp
  0x00000001189a0e58: sub    rsp,0x20           ;*synchronization entry
                                                ; - com.elastic.PartialEATest::allocate@-1 (line 26)

  0x00000001189a0e5c: mov    r11d,DWORD PTR [rsi+0x10]
                                                ;*getfield value {reexecute=0 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@1 (line 26)

  0x00000001189a0e60: mov    DWORD PTR [rsp],r11d
  0x00000001189a0e64: test   r11d,r11d
  0x00000001189a0e67: jle    0x00000001189a0ffc  ;*ifle {reexecute=0 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@4 (line 26)

  0x00000001189a0e6d: cmp    r11d,0xffffff80
  0x00000001189a0e71: jl     0x00000001189a100e  ;*if_icmplt {reexecute=0 rethrow=0 return_oop=0}
                                                ; - java.lang.Integer::valueOf@3 (line 1048)
                                                ; - com.elastic.PartialEATest::allocate@24 (line 26)

  0x00000001189a0e77: cmp    r11d,0x7f
  0x00000001189a0e7b: jg     0x00000001189a0ea9  ;*if_icmpgt {reexecute=0 rethrow=0 return_oop=0}
                                                ; - java.lang.Integer::valueOf@10 (line 1048)
                                                ; - com.elastic.PartialEATest::allocate@24 (line 26)

  0x00000001189a0e7d: mov    ebp,r11d
  0x00000001189a0e80: add    ebp,0x80           ;*iadd {reexecute=0 rethrow=0 return_oop=0}
                                                ; - java.lang.Integer::valueOf@20 (line 1049)
                                                ; - com.elastic.PartialEATest::allocate@24 (line 26)

  0x00000001189a0e86: cmp    ebp,0x100
  0x00000001189a0e8c: jae    0x00000001189a101e
  0x00000001189a0e92: movsxd r10,r11d
  0x00000001189a0e95: movabs r11,0x12ed02000    ;   {oop(a &#39;java/lang/Integer&#39;[256] {0x000000012ed02000})}
  0x00000001189a0e9f: mov    rbp,QWORD PTR [r11+r10*8+0x418]
                                                ;*aaload {reexecute=0 rethrow=0 return_oop=0}
                                                ; - java.lang.Integer::valueOf@21 (line 1049)
                                                ; - com.elastic.PartialEATest::allocate@24 (line 26)
................                                                
&lt;/code&gt;&lt;/pre&gt;
&lt;a href=&quot;https://gist.github.com/vladimirdolzhenko/4c17b4476bbb9c98cdd51f2c6ae1572e&quot;&gt;again - entire C2 generated code&lt;/a&gt;

&lt;h3&gt;Compiled method :: Graal&lt;/h3&gt;

The same trick but for &lt;b&gt;Graal&lt;/b&gt;&lt;br/&gt;
&lt;pre&gt;&lt;code&gt;ImmutableOopMap{rbx=Oop }pc offsets: 251 264 Compiled method (JVMCI)    1850 3888       4       com.elastic.PartialEATest::allocate (55 bytes)
 total in heap  [0x0000000119292590,0x0000000119292830] = 672
 relocation     [0x0000000119292708,0x0000000119292718] = 16
 main code      [0x0000000119292720,0x0000000119292795] = 117
 stub code      [0x0000000119292795,0x0000000119292798] = 3
 oops           [0x0000000119292798,0x00000001192927a0] = 8
 metadata       [0x00000001192927a0,0x00000001192927a8] = 8
 scopes data    [0x00000001192927a8,0x00000001192927c8] = 32
 scopes pcs     [0x00000001192927c8,0x0000000119292828] = 96
 dependencies   [0x0000000119292828,0x0000000119292830] = 8
----------------------------------------------------------------------
com/elastic/PartialEATest.allocate(Lorg/openjdk/jmh/infra/Blackhole;)V (com.elastic.PartialEATest.allocate(Blackhole))  [0x0000000119292720, 0x0000000119292798]  120 bytes
[Entry Point]
[Constants]
  # {method} {0x0000000231e007b8} &#39;allocate&#39; &#39;(Lorg/openjdk/jmh/infra/Blackhole;)V&#39; in &#39;com/elastic/PartialEATest&#39;
  # this:     rsi:rsi   = &#39;com/elastic/PartialEATest&#39;
  # parm0:    rdx:rdx   = &#39;org/openjdk/jmh/infra/Blackhole&#39;
  #           [sp+0x20]  (sp of caller)
  0x0000000119292720: cmp    rax,QWORD PTR [rsi+0x8]
  0x0000000119292724: jne    0x000000010eadc300  ;   {runtime_call ic_miss_stub}
  0x000000011929272a: nop
  0x000000011929272b: data16 data16 nop WORD PTR [rax+rax*1+0x0]
  0x0000000119292736: data16 nop WORD PTR [rax+rax*1+0x0]
[Verified Entry Point]
  0x0000000119292740: mov    DWORD PTR [rsp-0x14000],eax
  0x0000000119292747: sub    rsp,0x18
  0x000000011929274b: mov    QWORD PTR [rsp+0x10],rbp
  0x0000000119292750: cmp    DWORD PTR [rsi+0x10],0x1
  0x0000000119292754: jl     0x000000011929276d  ;*ifle {reexecute=0 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@4 (line 26)

  0x000000011929275a: mov    rbp,QWORD PTR [rsp+0x10]
  0x000000011929275f: add    rsp,0x18
  0x0000000119292763: mov    rcx,QWORD PTR [r15+0x70]
  0x0000000119292767: test   DWORD PTR [rcx],eax  ;   {poll_return}
  0x0000000119292769: vzeroupper 
  0x000000011929276c: ret                       ;*return {reexecute=0 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@54 (line 27)

  0x000000011929276d: mov    DWORD PTR [r15+0x314],0xffffffed
                                                ;*ifle {reexecute=0 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@4 (line 26)

  0x0000000119292778: mov    QWORD PTR [r15+0x320],0x0
  0x0000000119292783: call   0x000000010eadd2a4  ; ImmutableOopMap{rsi=Oop }
                                                ;*aload_0 {reexecute=1 rethrow=0 return_oop=0}
                                                ; - com.elastic.PartialEATest::allocate@0 (line 26)
                                                ;   {runtime_call DeoptimizationBlob}
  0x0000000119292788: nop
&lt;/code&gt;&lt;/pre&gt;

It is pretty obvious how is &lt;b&gt;C2&lt;/b&gt; generated code bigger than &lt;b&gt;Graal&lt;/b&gt; code. There are no any &lt;i&gt;autoboxing&lt;/i&gt; or &lt;i&gt;varargs&lt;/i&gt; in &lt;b&gt;Graal&lt;/b&gt; version - in fact just method call.

&lt;h2&gt; Outcome&lt;/h2&gt;

Seems &lt;b&gt;Graal&lt;/b&gt; makes lots of optimizations that we did manually. From one side it is still &lt;i&gt;experimental&lt;/i&gt; part of &lt;b&gt;openjdk&lt;/b&gt; and it takes some time to be enabled-by-default compiler - from another side - it is not clear what cases it can handle (esp. in comparison to &lt;b&gt;C2&lt;/b&gt;).</description><link>http://dolzhenko.blogspot.com/2018/04/guava-graal-and-partial-escape-analysis.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-2705340326349963259</guid><pubDate>Thu, 29 Mar 2018 19:20:00 +0000</pubDate><atom:updated>2018-03-29T22:23:50.389+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">java10</category><title>build hsdis with Java 10 on MacOsX</title><description>instructions to build &lt;b&gt;hsdis&lt;/b&gt; with java 10 - based on &lt;a href=&quot;https://www.chrisnewland.com/updated-instructions-for-building-hsdis-on-osx-417&quot;&gt;instructions for building hsdis on OSX (with java 9)&lt;/a&gt; 
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;bash&quot;&gt;$ hg clone http://hg.openjdk.java.net/jdk/jdk10/
$ cd jdk10/src/utils/hsdis
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.28.tar.bz2 
$ tar jxf binutils-2.28.tar.bz2
$ make BINUTILS=binutils-2.28 ARCH=amd64
$ sudo cp build/macosx-amd64/hsdis-amd64.dylib /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/lib/server
&lt;/code&gt;&lt;/pre&gt;

&lt;b&gt;Note&lt;/b&gt;: despite of hsdis/README it does NOT compile with binutils-2.17, nor binutils-2.19.1 neither with latest binutils-2.30. 
binutils-2.28 works fine on &lt;i&gt;High Sierra&lt;/i&gt;.</description><link>http://dolzhenko.blogspot.com/2018/03/build-hsdis-with-java-10-on-macosx.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-7656093938989289205</guid><pubDate>Sun, 13 Nov 2016 16:55:00 +0000</pubDate><atom:updated>2016-11-13T19:55:53.528+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><title>Java: All flags</title><description>Just to share my note - print out all &lt;b&gt;jvm&lt;/b&gt; flags 
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;bash&quot;&gt;$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version
&lt;/code&gt;&lt;/pre&gt;</description><link>http://dolzhenko.blogspot.com/2016/11/java-all-flags.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-2035775616982862777</guid><pubDate>Fri, 05 Feb 2016 15:27:00 +0000</pubDate><atom:updated>2016-02-14T00:07:38.614+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">unsafe</category><title>Java unsafe: copyMemory aligned vs unaligned</title><description>Давеча переводя проект на новые рельсы стала &lt;a href=&quot;https://twitter.com/dolzhenko/status/694900259563159552&quot;&gt;падать сборка&lt;/a&gt; - тесты проходят, а вот &lt;i&gt;jvm&lt;/i&gt; крешится.&lt;br/&gt; 
&lt;br/&gt;
Первое подозрение упало на наш alloc / dealloc поверх &lt;b&gt;Unsafe&lt;/b&gt; (да-да, кровь-кишки-камаз) - но в итоге все же стало ясно, что наши руки чистые и вина реально на C2 компиляторе и &lt;a href=&quot;http://trove.starlight-systems.com/&quot;&gt;трова&lt;/a&gt; стала тому причина - на эту тему две ошибки в C2 компиляторе: &lt;a href=&quot;https://bugs.openjdk.java.net/browse/JDK-8081379&quot;&gt;JDK-8081379&lt;/a&gt; и по мотивам этого же &lt;a href=&quot;https://bugs.openjdk.java.net/browse/JDK-6675699&quot;&gt;JDK-6675699&lt;/a&gt;.&lt;br/&gt;
&lt;br/&gt;
Однако, пока я винил наш alloc/dealloc смотрел - а не пытаемся ли мы деаллоцировать чего не нужного, соответственно стал писать адреса выделенной памяти и размеры. &lt;br/&gt;
Удивило, что очень много объектов без выравнивания по длине - например, 27 байт или там 253.&lt;br/&gt;
&lt;br/&gt;
Читаем &lt;a href=&quot;http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java#l532&quot;&gt;sun.misc.Unsafe#copyMemory&lt;/a&gt; и тут ребята заботливо пишут:&lt;br/&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;    /**
     * Sets all bytes in a given block of memory to a copy of another
     * block.
     *
     * This method determines each block&#39;s base address by means of two parameters,
     * and so it provides (in effect) a &lt;em&gt;double-register&lt;/em&gt; addressing mode,
     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
     * the offset supplies an absolute base address.
     *
     * The transfers are in coherent (atomic) units of a size determined
     * by the address and length parameters. &lt;span style=&quot;background:#8f8;&quot;&gt; If the effective addresses and
     * length are all even modulo 8, the transfer takes place in &#39;long&#39; units.&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;     * If the effective addresses and length are (resp.) even modulo 4 or 2,
     * the transfer takes place in units of &#39;int&#39; or &#39;short&#39;.&lt;/span&gt;
     *
     * @since 1.7
     */&lt;/code&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;

Более того, мистер Коваль накинул еще: 
&lt;div class=&quot;quote&quot;&gt;мол не только же длина, но и смещение играют роль - н.р если даже читать long, но он будет смещен на 1 байт относительно слова - то в итоге будут прочитаны два long.&lt;/div&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;b&gt;обновление 2015-02-13:&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;

Итак, куда же идет &lt;b&gt;Unsafe.copyMemory&lt;/b&gt; ? &lt;br/&gt;&lt;br/&gt;

Это нативный &lt;b&gt;jvm&lt;/b&gt; вызов:&lt;br/&gt;
копаем в сторону &lt;b&gt;unsafe.cpp&lt;/b&gt;: &lt;a href=&quot;http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/prims/unsafe.cpp#l650&quot;&gt;Unsafe_CopyMemory&lt;/a&gt;&lt;br/&gt;
потом &lt;a href=&quot;http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/utilities/copy.cpp#l30&quot;&gt;Copy::conjoint_memory_atomic&lt;/a&gt;&lt;br/&gt;
&lt;br/&gt;
и вот от момент откровения:
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;cpp&quot;&gt;
  uintptr_t bits = (uintptr_t) src | (uintptr_t) dst | (uintptr_t) size;

  if (bits % sizeof(jlong) == 0) {
&lt;span style=&quot;background:#8f8;&quot;&gt;    Copy::conjoint_jlongs_atomic((jlong*) src, (jlong*) dst, size / sizeof(jlong));&lt;/span&gt;
  } else if (bits % sizeof(jint) == 0) {
&lt;span style=&quot;background:#fcc;&quot;&gt;    Copy::conjoint_jints_atomic((jint*) src, (jint*) dst, size / sizeof(jint));&lt;/span&gt;
  } else if (bits % sizeof(jshort) == 0) {
&lt;span style=&quot;background:#faa;&quot;&gt;    Copy::conjoint_jshorts_atomic((jshort*) src, (jshort*) dst, size / sizeof(jshort));&lt;/span&gt;
  } else {
&lt;span style=&quot;background:#f88;&quot;&gt;    // Not aligned, so no need to be atomic.
    Copy::conjoint_jbytes((void*) src, (void*) dst, size);&lt;/span&gt;
  }
&lt;/code&gt;&lt;/pre&gt;
Если кратко, то &lt;b&gt;bits&lt;/b&gt; тогда и только тогда будет кратен размеру &lt;b&gt;long&lt;/b&gt;, когда и адрес источника, и адрес цели, и длина блока будут кратны размеру &lt;b&gt;long&lt;/b&gt;.
&lt;br/&gt;
&lt;br/&gt; 

&lt;a href=&quot;https://gist.github.com/vladimirdolzhenko/2fbd7b2d5dae9a58f806&quot;&gt;benchmark&lt;/a&gt;.&lt;br/&gt;
проверяет копирование в многопоточном режиме - 4 нитки. &lt;br/&gt;
&lt;br/&gt;Изначально производилось копирование из одного &lt;b&gt;общего&lt;/b&gt; (для всех нитей) куска памяти в другой &lt;b&gt;общий&lt;/b&gt; кусок памяти - и от этого получались странные цифры, что копирование 8 байт со смещением 0 такое же, как и копирование 8 байт со смещением 3 байта.&lt;br/&gt;
&lt;br/&gt;
В моем приложении другой шаблон использования - копирование происходит из &lt;b&gt;общего&lt;/b&gt; куска памяти в &lt;i&gt;&lt;b&gt;свой&lt;/b&gt;&lt;/i&gt; (н-р локальный массив байт) локальный кусок памяти.&lt;br/&gt;
&lt;br/&gt;
Результаты для 4х ниток:&lt;br/&gt;&lt;br/&gt;
&lt;pre class=&quot;code&quot;&gt;
Benchmark                    Mode  Samples   Score   Error  Units
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory253Bytes           avgt       15  13.023 ± 0.376  ns/op
copyMemory253BytesOffset3    avgt       15  13.189 ± 0.512  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory256Bytes           avgt       15  11.091 ± 0.304  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory256BytesOffset7    avgt       15  13.185 ± 0.066  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory27Bytes            avgt       15   9.034 ± 0.058  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory32Bytes            avgt       15   5.567 ± 0.154  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory32BytesOffset3     avgt       15   7.779 ± 0.080  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory4Bytes             avgt       15   6.801 ± 0.068  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory4BytesOffset3      avgt       15   7.760 ± 0.091  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory8Bytes             avgt       15   6.763 ± 0.044  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory8BytesOffset1      avgt       15   8.398 ± 0.154  ns/op
copyMemory8BytesOffset3      avgt       15   8.368 ± 0.083  ns/op
copyMemory8BytesOffset5      avgt       15   8.396 ± 0.079  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#ccc;&quot;&gt;readByteOffset0              avgt       15   3.067 ± 0.153  ns/op
readByteOffset3              avgt       15   3.024 ± 0.044  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#ccc;&quot;&gt;readIntOffset0               avgt       15   3.001 ± 0.037  ns/op
readIntOffset3               avgt       15   3.051 ± 0.150  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#ccc;&quot;&gt;readLongOffset0              avgt       15   2.997 ± 0.042  ns/op
readLongOffset3              avgt       15   2.993 ± 0.056  ns/op&lt;/span&gt;
&lt;/pre&gt;

и для 1 нитки
&lt;pre class=&quot;code&quot;&gt;
Benchmark                    Mode  Samples   Score   Error  Units
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory253Bytes           avgt       15  13.392 ± 0.580  ns/op
copyMemory253BytesOffset3    avgt       15  12.903 ± 0.304  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory256Bytes           avgt       15  11.195 ± 0.405  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory256BytesOffset7    avgt       15  13.446 ± 0.422  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory27Bytes            avgt       15   9.136 ± 0.266  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory32Bytes            avgt       15   5.513 ± 0.190  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory32BytesOffset3     avgt       15   7.830 ± 0.273  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory4Bytes             avgt       15   6.826 ± 0.204  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory4BytesOffset3      avgt       15   7.757 ± 0.223  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#8f8;&quot;&gt;copyMemory8Bytes             avgt       15   6.897 ± 0.221  ns/op&lt;/span&gt;
&lt;span style=&quot;background:#fcc;&quot;&gt;copyMemory8BytesOffset1      avgt       15   8.534 ± 0.276  ns/op
copyMemory8BytesOffset3      avgt       15   8.482 ± 0.285  ns/op
copyMemory8BytesOffset5      avgt       15   8.403 ± 0.262  ns/op&lt;/span&gt;

&lt;span style=&quot;background:#ccc;&quot;&gt;readByteOffset0              avgt       15   2.971 ± 0.104  ns/op
readByteOffset3              avgt       15   3.009 ± 0.115  ns/op

readIntOffset0               avgt       15   3.001 ± 0.125  ns/op
readIntOffset3               avgt       15   3.032 ± 0.113  ns/op

readLongOffset0              avgt       15   3.010 ± 0.100  ns/op
readLongOffset3              avgt       15   3.060 ± 0.094  ns/op&lt;/span&gt;
&lt;/pre&gt;

Т.е действительно для копирования очень важно, чтобы всё было по &lt;b&gt;восьмерке&lt;/b&gt;, тогда как для чтения это не имеет значения.
... meten is weten // голл. поговорка: измерение это знание</description><link>http://dolzhenko.blogspot.com/2016/02/java-unsafe-copymemory-aligned-vs.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-509161778091393970</guid><pubDate>Wed, 27 Mar 2013 19:25:00 +0000</pubDate><atom:updated>2013-03-28T00:43:05.408+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><title>java: конференция jpoint</title><description>Осталось чуть больше недели до независимой java конференции &lt;a href=&quot;http://javapoint.ru/&quot;&gt;jpoint&lt;/a&gt;, организованной энтузиастами &lt;a href=&quot;http://jug.ru/&quot;&gt;Java User Group&lt;/a&gt;, которая состоится 5го апреля 2013 года в &lt;a href=&quot;http://javapoint.ru/contacts/&quot;&gt;конгрессном центре “ПетроКонгресс”&lt;/a&gt; по адресу Санкт-Петербург, ул. Лодейнопольская, д. 5.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;img src=&quot;http://cs307211.vk.me/v307211606/5bbc/BsdJM2kzRDc.jpg&quot; border=&quot;0&quot;/&gt;&lt;br /&gt;
Святые угодники! Кто все эти люди ?!?&lt;/div&gt;&lt;br /&gt;
Я буду рассказывать о шишках и фишках, которые мы набили с &lt;i&gt;garbage collector&lt;/i&gt;ом, как мы научились не мешать друг другу работать, зачем родился на свет &lt;a href=&quot;https://bitbucket.org/vladimir.dolzhenko/gflogger/&quot;&gt;garbage free logger&lt;/a&gt;, а так же о своих наблюдениях и рекомендациях в оптимизации приложений с оглядкой на &lt;i&gt;gc&lt;/i&gt;, которые, надеюсь, будут полезные другим разработчикам. &lt;br /&gt;
&lt;br /&gt;
Организаторы сознательно сделали несколько шагов объявив конференцию для middle/senior разработчиков: &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Участие для слушателей в конференции платное. Деньги не космические, но это создаёт порог отсева толпы, пришедшей за халявой в виде бесплатных ручек и блокнотов&lt;/li&gt;
&lt;li&gt;Подбор тем докладов и самих докладчиков: определённо темы докладов для людей &amp;laquo;глубоко женатых&amp;raquo;, т.е для тех, у кого за плечами гораздо больше, чем &lt;i&gt;hello world&lt;/i&gt; и пары свистелок.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Мой предварительный план докладов, которые хочу послушать:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;i&gt;Динамическое обнаружение гонок в многопоточных Java-программах&lt;/i&gt; - ребята из &lt;i&gt;Devexperts&lt;/i&gt;, явно есть чему поучиться у них и узнать новые способы &lt;s&gt;варки автогеном&lt;/s&gt;тонкой работы в &lt;i&gt;java&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Java Runtime: повседневные обязанности виртуальной машины Java&lt;/i&gt; - очень мне близка тематика по духу, приятно удивлён, что и у нас есть горячие головы, которые лобзиком выпиливают &lt;i&gt;gc&lt;/i&gt; из &lt;i&gt;jvm&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;и быть может, холивное &lt;i&gt;Eclipse vs Intellij IDEA&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;хотел бы ещё сходить послушать &lt;i&gt;GC: Friend or foe&lt;/i&gt;, но ведь не дадут послушать...&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Ещё раз хотелось бы послать лучи поддержки организаторам - у нас всё получится !&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Дополнение&lt;/b&gt;&lt;/i&gt;. Организаторы обещают сделать видеозаписи докладов, которые после будут доступны в интернетах. Не спрашивайте меня когда, сколько и по чём.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;P.S.&lt;/b&gt; Да, и регистрация уже закрыта.</description><link>http://dolzhenko.blogspot.com/2013/03/javapoint.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-4153075545601847833</guid><pubDate>Fri, 15 Mar 2013 20:40:00 +0000</pubDate><atom:updated>2013-03-16T12:44:01.623+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">bash</category><category domain="http://www.blogger.com/atom/ns#">hints</category><title>Bash: Let me bash that for you, Part 2</title><description>Is your buffalo wings so spicy ?&lt;br /&gt;
&lt;br /&gt;
Lets juzz it up a bit more with bash !&lt;br /&gt;
&lt;br /&gt;
other parts of &amp;laquo;&lt;i&gt;let me bash that for you&amp;raquo;&lt;/i&gt; &lt;a href=&quot;http://dolzhenko.blogspot.com/2012/08/bash-let-me-bash-that-for-you-part-0.html&quot;&gt;Part 0&lt;/a&gt; and &lt;a href=&quot;http://dolzhenko.blogspot.com/2012/08/bash-let-me-bash-that-for-you-part-1.html&quot;&gt;Part I&lt;/a&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;var=&lt;/b&gt;&lt;br /&gt;
creates a &lt;i&gt;variable&lt;/i&gt; and assigns some value (e.g result command execution) to it for its future usages.&lt;br /&gt;
&lt;i&gt;Note:&lt;/i&gt; use a dollar sign (&lt;b&gt;$&lt;/b&gt;) to reference a variable&#39;s value&lt;br /&gt;
&lt;pre&gt;$ foo=&quot;FOO VARIABLE&quot; ; echo &quot;$foo $foo&quot;
FOO VARIABLE FOO VARIABLE&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;export &lt;i&gt;variable&lt;/i&gt;=&lt;i&gt;value&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
export the variable value for the future usage&lt;br /&gt;
&lt;pre&gt;$ export A=5
$ echo $A
5&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;set&lt;/b&gt;&lt;br /&gt;
prints out all known (assigned) variables (embedded functions) &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Note:&lt;/i&gt; The list of the most commonly used and significant variables &lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;b&gt;HOME&lt;/b&gt; home directory of the user, usually /home/&lt;i&gt;username&lt;/i&gt;
&lt;b&gt;PATH&lt;/b&gt; paths to look for executable commands
&lt;b&gt;LD_LIBRARY_PATH&lt;/b&gt; - paths to look for dynamic shared libraries an application has been linked against
&lt;b&gt;PWD&lt;/b&gt; (actual) working directory
&lt;b&gt;OLDPWD&lt;/b&gt; old working directory
&lt;b&gt;JAVA_HOME&lt;/b&gt; usually sets as java (jdk) directory

&lt;b&gt;USER&lt;/b&gt; current user login name
&lt;b&gt;UID&lt;/b&gt; current user&#39;s user identification number, as recorded in /etc/passwd
&lt;b&gt;HOSTNAME&lt;/b&gt; the name of the current host


&lt;b&gt;TMOUT&lt;/b&gt; if set to a value greater than &lt;b&gt;zero&lt;/b&gt;, bash terminates (log out) after that number of seconds if input does &lt;b&gt;not&lt;/b&gt; arrive


&lt;b&gt;$?&lt;/b&gt; exit value of last executed command.
&lt;b&gt;$!&lt;/b&gt; pid of last background command.


&lt;b&gt;$0&lt;/b&gt;, &lt;b&gt;$1&lt;/b&gt;, &lt;b&gt;$2&lt;/b&gt;, etc - positional parameters, passed from command line to script, passed to a function
&lt;b&gt;$*&lt;/b&gt;, &lt;b&gt;$@&lt;/b&gt; all parameters passed from command line to script ($1 $2 etc)
&lt;b&gt;$#&lt;/b&gt; number of command-line arguments or positional parameters


&lt;b&gt;$$&lt;/b&gt; pid of the current instance of shell
&lt;b&gt;PPID&lt;/b&gt; pid of parent process ( of the current instance of shell )
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;unset &lt;i&gt;variable&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
discards the &lt;b&gt;variable&lt;/b&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://tldp.org/LDP/abs/html/commandsub.html#BACKQUOTESREF&quot;&gt;`command`&lt;/a&gt;&lt;/b&gt; and &lt;b&gt;&lt;a href=&quot;http://tldp.org/LDP/abs/html/varassignment.html&quot;&gt;$(command)&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
variable assignment mechanism though a result of command execution &lt;pre class=&quot;code&quot;&gt;$ NOW=`date +&quot;%m-%d-%Y&quot;`; echo $NOW
03-16-2013
$ NOW2=$(date +&quot;%m-%d-%Y&quot;); echo $NOW2
03-16-2013
&lt;/pre&gt;&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?df&quot;&gt;df&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
reports disk space capacity/usage&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ df
Filesystem     1K-blocks     Used Available Use% Mounted on
rootfs          24776880 19823040   3715004  85% /
/dev/root       24776880 19823040   3715004  85% /
devtmpfs         1551036        0   1551036   0% /dev
tmpfs            1551228     2720   1548508   1% /run
cgroup_root        10240        0     10240   0% /sys/fs/cgroup
tmpfs             540672     5156    535516   1% /dev/shm
/dev/sda2       31814768 29868180    355852  99% /home
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; specifying &lt;i&gt;path&lt;/i&gt; get space usage of corresponding file system&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ df ~/workspace/
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda2       31814768 29868180    355852  99% /home
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; option &lt;b&gt;-h&lt;/b&gt; prints in human readable format&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ df -h ~/workspace/
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2        31G   29G  348M  99% /home
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; use &lt;b&gt;.&lt;/b&gt; (dot) to reffer actual file system&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ df -h .
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2        31G   29G  348M  99% /home
&lt;/pre&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?du&quot;&gt;du&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;
estimates file space usage&lt;pre class=&quot;code&quot;&gt;$ du myfile
4 myfile
$ du -h ~/workspace/docs/cs/java/langspec-3.0.pdf 
7.8M /home/user/workspace/docs/cs/java/langspec-3.0.pdf
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; option &lt;b&gt;-s&lt;/b&gt; displays summarized info&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ du -hs ~/workspace/docs/cs/java/
25M /home/user/workspace/docs/cs/java/
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?file&quot;&gt;file&lt;/a&gt;&lt;/b&gt; determines a file type by its content&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ file ~/workspace/docs/cs/java/langspec-3.0.pdf
/home/bob/workspace/docs/cs/java/langspec-3.0.pdf: PDF document, version 1.3
$ cp ~/workspace/docs/cs/java/langspec-3.0.pdf /tmp/xxx
$ file /tmp/xxx
/tmp/xxx: PDF document, version 1.3
$ bzip2 /tmp/xxx
$ file /tmp/xxx.bz2 
/tmp/xxx.bz2: bzip2 compressed data, block size = 900k
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?which&quot;&gt;which&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
shows the full path of command, it looks for it a command within &lt;b&gt;PATH&lt;/b&gt; environment variable: &lt;pre class=&quot;code&quot;&gt;$ which bash
/bin/bash
$ which java
/opt/sun-jdk-1.6.0.43/bin/java
$ which ls  
/bin/ls
&lt;/pre&gt;&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?ldd&quot;&gt;ldd&lt;/a&gt;&lt;/b&gt; - print shared library dependencies&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ ldd /opt/sun-jdk-1.6.0.43/bin/java
 linux-gate.so.1 (0xffffe000)
 libpthread.so.0 =&gt; /lib/libpthread.so.0 (0xb76d4000)
 libjli.so =&gt; /opt/sun-jdk-1.6.0.43/bin/../jre/lib/i386/jli/libjli.so (0xb76cb000)
 libdl.so.2 =&gt; /lib/libdl.so.2 (0xb76c7000)
 libc.so.6 =&gt; /lib/libc.so.6 (0xb754a000)
 /lib/ld-linux.so.2 (0xb7713000)
$ ldd `which sh`
 linux-gate.so.1 (0xffffe000)
 libreadline.so.6 =&amp;gt; /lib/libreadline.so.6 (0xb7730000)
 libncurses.so.5 =&amp;gt; /lib/libncurses.so.5 (0xb76e5000)
 libdl.so.2 =&amp;gt; /lib/libdl.so.2 (0xb76e1000)
 libc.so.6 =&amp;gt; /lib/libc.so.6 (0xb7564000)
 /lib/ld-linux.so.2 (0xb7794000)
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;That&#39;s &lt;b&gt;fork bomb&lt;/b&gt;, dudes: &lt;pre class=&quot;code&quot;&gt;:(){ :|:&amp;amp; };:&lt;/pre&gt;</description><link>http://dolzhenko.blogspot.com/2013/03/bash-let-me-bash-that-for-you-part-2.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-827845354856388207</guid><pubDate>Thu, 28 Feb 2013 13:41:00 +0000</pubDate><atom:updated>2016-01-15T15:09:26.701+03:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">linux</category><title>java: who has eaten my cpu ?</title><description>Приходит давеча коллега и показывает запущенное простенькое java приложение, которое &lt;i&gt;выжирает&lt;/i&gt; &amp;gt; 100% cpu без какой-либо на то видимой причины. &lt;br /&gt;
&lt;br /&gt;
Святые угодники! что делать ?&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;class code=&quot;bash&quot;&gt;$ ps  -o nlwp -p &lt;i&gt;&lt;b&gt;pid&lt;/b&gt;&lt;/i&gt;
NLWP
212&lt;/class&gt;&lt;/pre&gt;Количество ниток не запредельное, тоже мне невидаль, 212 ниток в java приложении. &lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;class code=&quot;bash&quot;&gt;$ kill -3 &lt;i&gt;&lt;b&gt;pid&lt;/b&gt;&lt;/i&gt;&lt;/class&gt;&lt;/pre&gt;&lt;br /&gt;
И читаем &lt;i&gt;thread dump&lt;/i&gt; в &lt;i&gt;stdout&lt;/i&gt;. И увы тоже ничего криминального не видим - &lt;i&gt;i/o&lt;/i&gt; работает, кто-то спит. Но! есть в это приложении один нюанс...&lt;br /&gt;
&lt;br /&gt;
Оно для некоторых своих целей использует... &lt;s&gt;карманный ядерный реактор&lt;/s&gt;&lt;b&gt;disruptor&lt;/b&gt; (но! это не &lt;b&gt;gflogger&lt;/b&gt;).&lt;br /&gt;
&lt;br /&gt;
А давайте-ка посмотрим, какие именно никти выедают ядра:&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;class code=&quot;bash&quot;&gt;$ ps -Lo pid,%cpu,lwp -p &lt;i&gt;&lt;b&gt;pid&lt;/b&gt;&lt;/i&gt; | grep -v &quot;LWP&quot; | awk &#39;{if ($2 &gt; 0.5){printf &quot;%d 0x%2x\n&quot;, $2, $3}}&#39;
35 0x24c
30 0x255
30 0x256
30 0x29D
20 0x2d0
18 0x35e
18 0x4f4
18 0x7e7&lt;/class&gt;&lt;/pre&gt;&lt;br /&gt;
Т.е получим информацию о потребении cpu &amp;gt; 0.5 на каждый &lt;i&gt;light weight process&lt;/i&gt; нашего приложения (и сразу в шестнадцатиричном виде).&lt;br /&gt;
&lt;br /&gt;
А это есть не что иное как &lt;b&gt;&lt;i&gt;nid&lt;/i&gt;&lt;/b&gt; нитки в нашем приложении, те самые &lt;b&gt;&lt;i&gt;native id&lt;/i&gt;&lt;/b&gt;, которые используются в &lt;i&gt;thread dump&lt;/i&gt; отчёте (kill -3):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&quot;XXXXExecutor1&quot; prio=10 tid=0x00007f29b58b7000 nid=&lt;b&gt;0x24c&lt;/b&gt; runnable [0x00007f29a6baa000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:317)
        at &lt;font color=&quot;red&quot;&gt;&lt;b&gt;com.lmax.disruptor.MultiThreadedClaimStrategy.waitForCapacity(MultiThreadedClaimStrategy.java:186)&lt;/b&gt;&lt;/font&gt;
        at com.lmax.disruptor.MultiThreadedClaimStrategy.incrementAndGet(MultiThreadedClaimStrategy.java:116)
        at com.lmax.disruptor.Sequencer.next(Sequencer.java:126)
        at XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

&quot;XXXXExecutor2&quot; prio=10 tid=0x00007f29b4bee800 nid=&lt;b&gt;0x255&lt;/b&gt; runnable [0x00007f29a67a6000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:317)
        at &lt;font color=&quot;red&quot;&gt;&lt;b&gt;com.lmax.disruptor.MultiThreadedClaimStrategy.waitForCapacity(MultiThreadedClaimStrategy.java:186)&lt;/b&gt;&lt;/font&gt;
        at com.lmax.disruptor.MultiThreadedClaimStrategy.incrementAndGet(MultiThreadedClaimStrategy.java:116)
        at com.lmax.disruptor.Sequencer.next(Sequencer.java:126)
        at XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

&quot;XXXXExecutor3&quot; prio=10 tid=0x00007f29b4bf0800 nid=&lt;b&gt;0x256&lt;/b&gt; runnable [0x00007f29a66a5000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:317)
        at &lt;font color=&quot;red&quot;&gt;&lt;b&gt;com.lmax.disruptor.MultiThreadedClaimStrategy.waitForCapacity(MultiThreadedClaimStrategy.java:186)&lt;/b&gt;&lt;/font&gt;
        at com.lmax.disruptor.MultiThreadedClaimStrategy.incrementAndGet(MultiThreadedClaimStrategy.java:116)
        at com.lmax.disruptor.Sequencer.next(Sequencer.java:126)
        at XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

&lt;/pre&gt;&lt;br /&gt;
И конечно же виноват не сам &lt;b&gt;disruptor&lt;/b&gt;, а какой-то &lt;s&gt;му&lt;/s&gt;чудак, который не правильно его заиспользовал.</description><link>http://dolzhenko.blogspot.com/2013/02/java-high-cpu-consumption-investigation.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6457557925082043579</guid><pubDate>Thu, 03 Jan 2013 11:52:00 +0000</pubDate><atom:updated>2013-01-03T15:52:39.713+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datastructures</category><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачка: Перестановки в массиве</title><description>&lt;div class=&quot;quote&quot;&gt;Дан массив&lt;br /&gt;
&lt;b&gt;[&lt;/b&gt; a&lt;sub&gt;1&lt;/sub&gt;, a&lt;sub&gt;2&lt;/sub&gt;, ... a&lt;sub&gt;n&lt;/sub&gt;, b&lt;sub&gt;1&lt;/sub&gt;,     b&lt;sub&gt;2&lt;/sub&gt;, ... b&lt;sub&gt;n&lt;/sub&gt;  &lt;b&gt;]&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Необходимо переставить элементы в массиве, так, чтобы получился&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;[&lt;/b&gt; a&lt;sub&gt;1&lt;/sub&gt;, b&lt;sub&gt;1&lt;/sub&gt;, a&lt;sub&gt;2&lt;/sub&gt;, b&lt;sub&gt;2&lt;/sub&gt;, ... a&lt;sub&gt;n&lt;/sub&gt;,  b&lt;sub&gt;n&lt;/sub&gt;  &lt;b&gt;]&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;замечание:&lt;/i&gt; дополнительная память &lt;b&gt;O&lt;/b&gt;(1), сложность &amp;lt; &lt;b&gt;O&lt;/b&gt;(n&lt;sup&gt;2&lt;/sup&gt;)&lt;/div&gt;</description><link>http://dolzhenko.blogspot.com/2013/01/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-2174712021407413931</guid><pubDate>Thu, 20 Dec 2012 19:52:00 +0000</pubDate><atom:updated>2012-12-22T20:47:34.157+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачка: зеркально отразить битовое представление</title><description>&lt;div class=&quot;quote&quot;&gt;Как можно зеркально отобразить битовое представление &lt;i&gt;8 битного&lt;/i&gt; числа ? &lt;i&gt;16 битного&lt;/i&gt; числа ?&lt;br /&gt;
&lt;br /&gt;
Например,&lt;br /&gt;
&lt;b&gt;M&lt;/b&gt;(123&lt;sub&gt;10&lt;/sub&gt;) = &lt;b&gt;M&lt;/b&gt;(01111011&lt;sub&gt;2&lt;/sub&gt;) = 11011110&lt;sub&gt;2&lt;/sub&gt; = 222&lt;sub&gt;10&lt;/sub&gt;.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;внимание!&lt;/span&gt;  комментарии содержат ответ.</description><link>http://dolzhenko.blogspot.com/2012/12/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-7484349992025153057</guid><pubDate>Mon, 26 Nov 2012 21:23:00 +0000</pubDate><atom:updated>2013-01-03T20:21:51.028+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datastructures</category><category domain="http://www.blogger.com/atom/ns#">java</category><title>java: Adaptive throttling, Part 1</title><description>&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYP7-zR9Tih9E0YGa-4FiOlHCrSLEnLo1DHFtroNDXI1DbGH9f3B-S3HAjKdoEE8tvOIvDIfxoa9DpLjZVCu6ytiI6BqRFff-MIqzcBTkqnyM8lZ4FvkzFleKZqoAmY3Ji7iXerIyVoA/s360/throttle1.png&quot; style=&quot;float:left;margin:0 20px 0px 20px;&quot;/&gt; &lt;br /&gt;
Типичная проблема, которая возникает при обработке большого потока сообщений:&lt;br /&gt;
&lt;br /&gt;
- нельзя пропихнуть большого слона через маленькую трубу, т.е. обработка сообщений не успевает &lt;i&gt;&amp;laquo;проглотить&amp;raquo;&lt;/i&gt; все сообщения&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При этом существуют некоторые ограничения на поток данных :&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;поток не равномерный и состоит из событий разного типа&lt;/li&gt;
&lt;li&gt;количество типов событий заранее не известно, но конечное число&lt;/li&gt;
&lt;li&gt;каждый тип события имеет свою &lt;i&gt;актуальность&lt;/i&gt; во времени&lt;/li&gt;
&lt;li&gt;все типы событий имеют равный приоритет&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
На диаграмме приведён пример разрешения проблемы: &lt;i&gt;нагребатор&amp;#0153;&lt;/i&gt;  работает на нитке &lt;b&gt;T&lt;sub&gt;1&lt;/sub&gt;&lt;/b&gt;, а следовательно &lt;i&gt;разгребатор&amp;#0153;&lt;/i&gt;  на нитке &lt;b&gt;T&lt;sub&gt;2&lt;/sub&gt;&lt;/b&gt;&lt;ul&gt;&lt;li&gt;за время обработки события типа &lt;b&gt;A&lt;/b&gt; успевают прийти новые события как типа &lt;b&gt;B&lt;/b&gt;, так и &lt;b&gt;A&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;после обработки события типа &lt;b&gt;B&lt;/b&gt; необходимо обработать наиболее актуальное событие типа &lt;b&gt;A&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Проблема осложняется ещё тем, что может быть несколько &lt;i&gt;нагребаторов&amp;#0153;&lt;/i&gt;, при этом каждый &lt;i&gt;нагребатор&amp;#0153;&lt;/i&gt; может порождать только события одного типа; так и есть потребность в нескольких &lt;i&gt;разгребаторах&amp;#0153;&lt;/i&gt; - при этом &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Терминология.&lt;/i&gt; &lt;i&gt;Stream&lt;/i&gt; есть &lt;i&gt;поток данных&lt;/i&gt;, тогда как &lt;i&gt;thread&lt;/i&gt; есть &lt;i&gt;нитка&lt;/i&gt; или &lt;i&gt;нить выполнения&lt;/i&gt;. И не стоит путать потоки с нитками.&lt;br /&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
На мой взгляд задача очень интересная, вполне практическая и более того - из нашей специфики работы. &lt;br /&gt;
&lt;br /&gt;
Именно поэтому, мы с &lt;a href=&quot;http://cheremin.blogspot.com/&quot;&gt;Русланом&lt;/a&gt; задаём нашим кандидатам на собеседовании - т.е не буквально закодить всё от и до, но хотя бы построить дизайн решения, освещая ключевые моменты решения кусками кода. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Небольшое лирическое отступление: я не считаю, что стоит задавать на собеседовании вопросы типа &amp;laquo;какие есть методы у java.lang.Object ?&amp;raquo; или &amp;laquo;какова сложность алгоритма поиска в hash структуре?&amp;raquo; - комплексные практические задачи, подобные вышеописанной, позволяют обсудить широкий спектр вопросов - от сложности алгоритмов и concurrency, до проектирования и архитектуры в целом.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Поскольку всё уже закожено, и быть может осталось навести небольшой марафет, опишу ключевые моменты решения&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;i&gt;open addressing&lt;/i&gt;: структура данных &lt;i&gt;hash&lt;/i&gt; ассоциативный массив с &lt;i&gt;открытой адресацией&lt;/i&gt;:&lt;ul&gt;&lt;li&gt;одномерный массив сущностей&lt;/li&gt;
&lt;li&gt;сущность наследует &lt;i&gt;atomic reference&lt;/i&gt;: дополнительное свойство - ключ, тип сообщения, определяет индекс в массиве. Значение (само событие) хранится по &lt;i&gt;atomic reference&lt;/i&gt;, причём оно будет всегда самым актуальным значением, при обработке достаточно сделать &lt;i&gt;getAndSet(null)&lt;/i&gt;, тем самым пометив, как обработанное&lt;/li&gt;
&lt;li&gt;ограниченное небольшое количество проб для устранения &lt;i&gt;hash&lt;/i&gt; коллизий, например, 3-4&lt;/li&gt;
&lt;li&gt;необходимые расширения массива, размер которого можно поддерживать как 2&lt;sup&gt;K&lt;/sup&gt; (быстрое получение индекса), и заполнение ячеек происходят под &lt;i&gt;монитором&lt;/i&gt; в начальной фазе&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;card marking&lt;/i&gt;: каждый изменённый элемент массива помечает соответствующий ему сегмент как &lt;i&gt;dirty&lt;/i&gt;. Например, сегмент = 1/64 часть массива, маркер изменений - соответствующий бит в &lt;i&gt;atomic long&lt;/i&gt;. &lt;/li&gt;
&lt;li&gt;&lt;i&gt;waiting stategy&lt;/i&gt;: не стоит сразу впадать в состояние &lt;i&gt;пассивного ожидания&lt;/i&gt; (на мониторе) если нет изменений, вполне возможно, что удастся получить   изменение активно &lt;i&gt;poll&lt;/i&gt;&#39;я флаг &lt;i&gt;card marking&lt;/i&gt;&#39;а.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Т.о. решена ещё и проблема нескольких &lt;i&gt;нагребаторов&amp;#0153;&lt;/i&gt; - каждый их них попадает в разные элементы массива и не создают &lt;i&gt;contention&lt;/i&gt; между собой. Так же решена проблема и &lt;i&gt;разгребаторов&amp;#0153;&lt;/i&gt; - пока один будет обрабатывать одну серию изменений, второй может не только обрабатать новые задачи, но и стащить задачи из списка задач, предназначенных для других, т.о. получается ещё на сдачу и &lt;i&gt;load balancing&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Any ideas?&lt;/i&gt;&lt;/b&gt;</description><link>http://dolzhenko.blogspot.com/2012/11/java-adaptive-throttling.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbYP7-zR9Tih9E0YGa-4FiOlHCrSLEnLo1DHFtroNDXI1DbGH9f3B-S3HAjKdoEE8tvOIvDIfxoa9DpLjZVCu6ytiI6BqRFff-MIqzcBTkqnyM8lZ4FvkzFleKZqoAmY3Ji7iXerIyVoA/s72-c/throttle1.png" height="72" width="72"/><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6621361401034804681</guid><pubDate>Tue, 13 Nov 2012 21:13:00 +0000</pubDate><atom:updated>2012-11-27T09:01:30.407+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">jni</category><category domain="http://www.blogger.com/atom/ns#">time</category><title>java: nanoTime</title><description>&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvUfmWrGsyMkkSYT1YJZmTtB5C52U4UodBhIuU8-4BFOs-QnU4Ffq0fYCqmc1-3Y9XkzEwEg8l7AMUG8nDH4eNIW0uV1AqPLzHo3VV_iE7Vw3H3qxRBq7ho_3hW4__FQOEb1s3krTSM-Y/s220/wall-clock.png&quot; style=&quot;float:left;margin:0 10px 10px 0;&quot;/&gt; Пока &lt;a href=&quot;http://www.javaspecialist.ru/&quot;&gt;одни&lt;/a&gt; заливали соляру в &lt;a href=&quot;http://lurkmore.to/%D0%9F%D0%BE%D1%80%D0%BE%D1%81%D1%91%D0%BD%D0%BE%D0%BA_%D0%9F%D1%91%D1%82%D1%80#.D0.A1.D1.80.D0.B0.D0.BD.D1.8B.D0.B9_.D1.82.D1.80.D0.B0.D0.BA.D1.82.D0.BE.D1.80&quot;&gt;трактор&lt;/a&gt;, мы продолжаем копаться в своём. &lt;br /&gt;
&lt;br /&gt;
Тёма очень хорошо написал о &lt;a href=&quot;http://www.javaspecialist.ru/2012/04/system.html&quot;&gt;измерении времени в java&lt;/a&gt; с ссылками на источники, так, что казалось бы и добавить нечего, но вставлю я свои пять копеек.&lt;br /&gt;
&lt;br /&gt;
Все мы хорошо знаем метод &lt;i&gt;System.nanoTime()&lt;/i&gt;&lt;br /&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;
    /**
     * Returns the current value of the most precise available system
     * timer, in nanoseconds.
     *
     * &lt;i&gt;This method can only be used to measure elapsed time and is
     * not related to any other notion of &lt;b&gt;system or wall-clock time&lt;/b&gt;.
     * The value returned represents nanoseconds since some fixed but
     * arbitrary time (perhaps in the future, so values may be
     * negative).  This method provides nanosecond precision, but not
     * necessarily nanosecond accuracy. No guarantees are made about
     * how frequently values change. Differences in successive calls
     * that span greater than approximately 292 years (2&lt;sup&gt;63&lt;/sup&gt;
     * nanoseconds) will not accurately compute elapsed time due to
     * numerical overflow.&lt;/i&gt;
     *
     * For example, to measure how long some code takes to execute:
     * 
     *   long startTime = System.nanoTime();
     *   // ... the code being measured ...
     *   long estimatedTime = System.nanoTime() - startTime;
     * 
     * 
     * @return The current value of the system timer, in nanoseconds.
     * @since 1.5
     */
    public static native long nanoTime();
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
И не смотря на то, что его абсолютные значения слабо связаны с какой-либо начальной точкой во времени, возникают соблазны (чего уж там, и я грешен) сделать гибрид из &lt;i&gt;nanoTime()&lt;/i&gt; и &lt;i&gt;currentTimeMillis()&lt;/i&gt; - используя последний получить некоторый &lt;i&gt;offset&lt;/i&gt; относительно начала эпохи, а &lt;i&gt;nanos&lt;/i&gt; в серии измений, чтобы получать разрешение хотя бы микросекундной точности. &lt;br /&gt;
&lt;br /&gt;
Всё бы ничего, если бы не очень важное замечание в &lt;i&gt;javadoc&lt;/i&gt; метода &lt;i&gt;nanoTime()&lt;/i&gt; - данные значения никак не связаны с системными или &lt;i&gt;настенными&lt;/i&gt; часами. &lt;br /&gt;
&lt;br /&gt;
Напрашивается вопрос - с чем же тогда значение связано и как его правильно использовать. &lt;br /&gt;
&lt;br /&gt;
Ответ, вполне очевидный многим - значения берутся из &lt;i&gt;некоторого&lt;/i&gt; внутреннего счётчика, это вполне может быть uptime в gnu/linux, или что-нибудь ещё, что взбрело в голову. &lt;br /&gt;
&lt;br /&gt;
Что же касается рамок корректности значений - дабы удешевить данную операцию, нужно использовать некоторые внутрипроцессорные, а ещё лучше внутриядерные счётчики, например, количество тиков с момента запуска процессора. &lt;br /&gt;
&lt;br /&gt;
На &lt;i&gt;x86&lt;/i&gt; архитектуре это выполняется инструкцией &lt;i&gt;&lt;b&gt;R&lt;/b&gt;ea&lt;b&gt;d&lt;/b&gt; &lt;b&gt;T&lt;/b&gt;ime &lt;b&gt;S&lt;/b&gt;tamp &lt;b&gt;C&lt;/b&gt;ounter&lt;/i&gt;, которая имеет обширный &lt;a href=&quot;http://ru.wikipedia.org/wiki/Rdtsc#.D0.9F.D1.80.D0.BE.D0.B1.D0.BB.D0.B5.D0.BC.D1.8B_.D0.B8.D1.81.D0.BF.D0.BE.D0.BB.D1.8C.D0.B7.D0.BE.D0.B2.D0.B0.D0.BD.D0.B8.D1.8F&quot;&gt;ряд проблем&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Т.о. последовательные вызовы &lt;i&gt;nanoTime()&lt;/i&gt; корректны &lt;b&gt;не в пределах одной &lt;i&gt;jvm&lt;/i&gt;&lt;/b&gt;, сколько &lt;b&gt;в пределах одного ядра &lt;i&gt;cpu&lt;/i&gt; внутри одной &lt;i&gt;jvm&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Небольшой &lt;a href=&quot;https://gist.github.com/4045415&quot;&gt;эксперимент&lt;/a&gt; по изменению разницы &lt;i&gt;nanoTime()&lt;/i&gt; на 50 нитках наглядно демонстрирует разброс: &lt;pre class=&quot;code&quot;&gt;T1 - T0 : -603.036 ms
T2 - T1 : 3.034 ms
T3 - T2 : 598.562 ms
T4 - T3 : -600.522 ms
T5 - T4 : 612.359 ms
T6 - T5 : -610.809 ms
T7 - T6 : 610.947 ms
T8 - T7 : -610.722 ms
T9 - T8 : 601.671 ms
T10 - T9 : -464.732 ms
T11 - T10 : 456.234 ms
T12 - T11 : -458.359 ms
T13 - T12 : 455.293 ms
T14 - T13 : -456.188 ms
T15 - T14 : 456.052 ms
T16 - T15 : 5.646 ms
T17 - T16 : -353.449 ms
T18 - T17 : 353.424 ms
T19 - T18 : -457.635 ms
T20 - T19 : 462.279 ms
T21 - T20 : -460.684 ms
T22 - T21 : 457.1 ms
T23 - T22 : -459.267 ms
T24 - T23 : 453.619 ms
T25 - T24 : 5.864 ms
T26 - T25 : -3.459 ms
T27 - T26 : 4.51 ms
T28 - T27 : -1.376 ms
T29 - T28 : 0.453 ms
T30 - T29 : 1.867 ms
T31 - T30 : -9.318 ms
T32 - T31 : -452.341 ms
T33 - T32 : 460.413 ms
T34 - T33 : 12.483 ms
T35 - T34 : -14.287 ms
T36 - T35 : 14.254 ms
T37 - T36 : 0.758 ms
T38 - T37 : -10.808 ms
T39 - T38 : 0.285 ms
T40 - T39 : -5.638 ms
T41 - T40 : -1.892 ms
T42 - T41 : 17.851 ms
T43 - T42 : -19.797 ms
T44 - T43 : 19.406 ms
T45 - T44 : -12.41 ms
T46 - T45 : 2.643 ms
T47 - T46 : -5.896 ms
T48 - T47 : 4.104 ms
T49 - T48 : -599.48 ms&lt;/pre&gt;&lt;br /&gt;
Т.о. гидра из &lt;i&gt;nanoTime()&lt;/i&gt; и &lt;i&gt;currentTimeMillis()&lt;/i&gt; будучи использована в разных нитках способна наверняка преподнести сюрпризы.&lt;br /&gt;
&lt;br /&gt;
Счастье не наступило, и у нас нет в руках инструмента, чтобы замерять время в &lt;i&gt;java&lt;/i&gt; с микросекундной точностью.&lt;br /&gt;
&lt;h4&gt;Keep calm and carry on.&lt;/h4&gt;Заглянув под &lt;a href=&quot;http://stas-blogspot.blogspot.ru/2012/02/what-is-behind-systemnanotime.html&quot;&gt;капот System.nanoTime()&lt;/a&gt;, кому лень - те смотрят в исходники &lt;i&gt;openjdk&lt;/i&gt;, например, &lt;i&gt;openjdk/hotspot/src/os/linux/vm/os_linux.cpp&lt;/i&gt; &lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;c&quot;&gt;jlong os::javaTimeNanos() {
  if (Linux::supports_monotonic_clock()) {
    struct timespec tp;
    int status = Linux::&lt;a href=&quot;http://linux.die.net/man/3/clock_gettime&quot;&gt;clock_gettime&lt;/a&gt;(CLOCK_MONOTONIC, &amp;amp;tp);
    assert(status == 0, &quot;gettime error&quot;);
    jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
    return result;
  } else {
    timeval time;
    int status = &lt;a href=&quot;http://linux.die.net/man/3/gettimeofday&quot;&gt;gettimeofday&lt;/a&gt;(&amp;amp;time, NULL);
    assert(status != -1, &quot;linux error&quot;);
    jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
    return 1000 * usecs;
  }
}&lt;/code&gt;&lt;/pre&gt;и &lt;i&gt;System.currentTimeMillis()&lt;/i&gt;: &lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;c&quot;&gt;
jlong os::javaTimeMillis() {
  timeval time;
  int status = &lt;a href=&quot;http://linux.die.net/man/3/gettimeofday&quot;&gt;gettimeofday&lt;/a&gt;(&amp;amp;time, NULL);
  assert(status != -1, &quot;linux error&quot;);
  return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);
}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Разбираемся с &lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;c&quot;&gt;int &lt;a href=&quot;http://linux.die.net/man/3/clock_gettime&quot;&gt;clock_gettime&lt;/a&gt;(clockid_t clk_id, struct timespec *tp);&lt;/code&gt;&lt;/pre&gt;где &lt;i&gt;clk_id&lt;/i&gt; идентификатор используемых часов, а &lt;i&gt;timespec&lt;/i&gt; - структура секунда - наносекунда:&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;c&quot;&gt;struct timespec {
        time_t   tv_sec;        /* seconds */
        long     tv_nsec;       /* nanoseconds */
};&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Вся соль в &lt;i&gt;clk_id&lt;/i&gt;:&lt;br /&gt;
&lt;h4&gt;CLOCK_REALTIME&lt;/h4&gt;Системные &lt;i&gt;&amp;laquo;настенные&amp;raquo;&lt;/i&gt; часы, предоставляющие время с начала эпохи.&lt;br /&gt;
&lt;h4&gt;CLOCK_MONOTONIC&lt;/h4&gt;Монотонные часы относительно некоторого не специфицированного момента времени. Именно &lt;b&gt;CLOCK_MONOTONIC&lt;/b&gt; использует инструкцию &lt;b&gt;RDTSC&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;(и ещё пара не столь важных для нас значений типа &lt;b&gt;CLOCK_PROCESS_CPUTIME_ID&lt;/b&gt; и &lt;b&gt;CLOCK_THREAD_CPUTIME_ID&lt;/b&gt;.)&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
И вот мы почти на финише, объявляем &lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;public final class PreciseTimestamp {

    static {
        try {
            System.loadLibarary(&quot;precisetimestamp&quot;);
        } catch (Throwable e){
           // bla-bla-bla
        }
    }

    public static native long getMicros();

}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
В &lt;i&gt;long&lt;/i&gt; можно уложить разницы в 292471 лет с точностью до микросекунды, на первое время должно хватить.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;javah&lt;/i&gt; создаёт из &lt;i&gt;java&lt;/i&gt; класса &lt;i&gt;c/c++&lt;/i&gt; заголовок, &lt;i&gt;*nix&lt;/i&gt; реализация:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;c&quot;&gt;#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;sys/time.h&amp;gt;
#include &amp;lt;time.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &quot;PreciseTimestamp.h&quot;

JNIEXPORT jlong JNICALL Java_PreciseTimestamp_getMicros
  (JNIEnv * env, jclass jc)
{
#if defined(_POSIX_TIMERS)
  {
    struct timespec ts;
    if ( 0 == clock_gettime(CLOCK_REALTIME, &amp;ts) )
    {
      return ((((jlong) ts.tv_sec) * 1000000) +
             (((jlong) ts.tv_nsec)) / 1000);
    }
  }
#endif

  // otherwise use gettimeofday

  struct timeval tv;
  gettimeofday(&amp;amp;tv, NULL);
  return (((jlong) tv.tv_sec) * 1000000) + ((jlong) tv.tv_usec);
}
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
И с силой &lt;s&gt;божьей&lt;/s&gt;&lt;i&gt;gcc&lt;/i&gt; собираем, запускаем и наслаждаемся &lt;i&gt;микросекундным&lt;/i&gt; таймером, который можно смело использовать не только в разных нитках, но и разных &lt;i&gt;jvm&lt;/i&gt;, и на разных боксах, с учётом того, что они синхронизируются, т.к &lt;a href=&quot;http://www.ietf.org/rfc/rfc1305.txt&quot;&gt;ntp&lt;/a&gt; согласно спецификации может предоставлять микросекундную точность.&lt;br /&gt;
&lt;br /&gt;
Поднимая разговор о &lt;i&gt;ntp&lt;/i&gt; нельзя не отметить, что он вносит изменения в значения &lt;b&gt;CLOCK_REALTIME&lt;/b&gt;, т.е. в моменты синхронизации можем получать странные значения, в т.ч. и отрицательные.&lt;br /&gt;
&lt;br /&gt;
Тонкие ценители прекрасного могли бы, конечно, воспользоваться не &lt;i&gt;jni&lt;/i&gt;, а &lt;i&gt;jna&lt;/i&gt;, но не стоит пренебрегать рекомендацией авторов &lt;i&gt;jna&lt;/i&gt; - каждый вызов тяжелее ~ 0.1 мс, что не пригодно для поставленной цели.</description><link>http://dolzhenko.blogspot.com/2012/11/java-nanotime.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvUfmWrGsyMkkSYT1YJZmTtB5C52U4UodBhIuU8-4BFOs-QnU4Ffq0fYCqmc1-3Y9XkzEwEg8l7AMUG8nDH4eNIW0uV1AqPLzHo3VV_iE7Vw3H3qxRBq7ho_3hW4__FQOEb1s3krTSM-Y/s72-c/wall-clock.png" height="72" width="72"/><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6847367222217282360</guid><pubDate>Tue, 13 Nov 2012 21:13:00 +0000</pubDate><atom:updated>2012-11-16T21:50:25.331+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datastructures</category><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачка: развернуть односвязанный список</title><description>&lt;div class=&quot;quote&quot;&gt;Задан односвязанный список, например:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;A&lt;/b&gt; -&amp;gt; &lt;b&gt;B&lt;/b&gt; -&amp;gt; &lt;b&gt;C&lt;/b&gt; -&amp;gt; ... -&amp;gt; &lt;b&gt;X&lt;/b&gt; -&amp;gt; &lt;b&gt;Y&lt;/b&gt; -&amp;gt; &lt;b&gt;Z&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Необходимо &lt;i&gt;развернуть&lt;/i&gt; список, т.е, чтобы его крайний элемент стал первым, предпоследний вторым, и т.д, и в конце концов, первый элемент стал бы крайним элементом.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Z&lt;/b&gt; -&amp;gt; &lt;b&gt;Y&lt;/b&gt; -&amp;gt; &lt;b&gt;X&lt;/b&gt; -&amp;gt; ... -&amp;gt; &lt;b&gt;C&lt;/b&gt; -&amp;gt; &lt;b&gt;B&lt;/b&gt; -&amp;gt; &lt;b&gt;A&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Сложность: &lt;b&gt;O(N)&lt;/b&gt;, доступная память: &lt;b&gt;O(1)&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;замечание:&lt;/i&gt; можно модифицировать исходный список.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;внимание!&lt;/span&gt;  комментарии содержат ответ.</description><link>http://dolzhenko.blogspot.com/2012/11/linked-list.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-2056472412810129065</guid><pubDate>Tue, 13 Nov 2012 21:13:00 +0000</pubDate><atom:updated>2012-11-14T01:13:33.386+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">garbage</category><category domain="http://www.blogger.com/atom/ns#">gc</category><category domain="http://www.blogger.com/atom/ns#">java</category><title>java: garbage less</title><description>За время написания &lt;a href=&quot;https://bitbucket.org/vladimir.dolzhenko/gflogger/&quot;&gt;&lt;i&gt;gflogger&lt;/i&gt;&lt;/a&gt; и борьбой за &lt;i&gt;low latency&lt;/i&gt; в &lt;i&gt;java&lt;/i&gt; накопился некоторый опыт о том как меньше плодить мусора и тем самым меньше нагружать &lt;i&gt;сборщик мусора&lt;/i&gt;, и как следствие, меньше влиять на производительность самого приложения. &lt;br /&gt;
&lt;br /&gt;
Такому тонкому &lt;s&gt;тролли&lt;/s&gt;подходу придумали специальный термин &lt;b&gt;&lt;i&gt;garbage less design&lt;/i&gt;&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
Впрочем, существую и некоторые другие вариации как заставить &lt;i&gt;garbage collector&lt;/i&gt; меньше мешать нам жить.&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Что следует избегать&lt;/h2&gt;&lt;h4&gt;autoboxing&lt;/h4&gt;Тут скорее авторы &lt;i&gt;java&lt;/i&gt; пошли на поводу у миллионов леммингов, орущих дайте мне сахара, да побольше, побольше! &lt;br /&gt;
&lt;br /&gt;
Чем плох &lt;i&gt;autoboxing&lt;/i&gt; ? Самое очевидное, тем, что он создаёт &lt;i&gt;overhead&lt;/i&gt; по памяти: так если &lt;i&gt;long&lt;/i&gt; занимает 8 байт (причём на стеке, если это локальная переменная или аргумент метода), тогда как экземпляр &lt;i&gt;java.lang.Long&lt;/i&gt; занимает уже 16 байт и всегда (~ почти всегда) на куче. &lt;br /&gt;
&lt;br /&gt;
Теперь, о не очевидном: можно смело отбросить то, что будут вызываться методы для обращения к подлежащему примитиву (н-р метод &lt;i&gt;longValue()&lt;/i&gt; у  &lt;i&gt;java.lang.Long&lt;/i&gt;) поскольку такие методы отлично &lt;i&gt;inline&lt;/i&gt;&#39;ятся. &lt;br /&gt;
&lt;br /&gt;
Но прежде всего это создание нового узла для &lt;i&gt;сборщика мусора&lt;/i&gt; - даже если экземпляр обёртки будет жить быстро и умрёт молодым, сборщику придётся немного потрудится, что потенциально может привести к ооочень незначительной остановке всего приложения.&lt;br /&gt;
&lt;br /&gt;
Самое интересное во всём этом, то, что не только смерть молодых останавливает время, но и рождение может спровоцировать нечто подобное. &lt;br /&gt;
На это тонко и деликатно намекает зубр &lt;s&gt;рок&lt;/s&gt; java &lt;i&gt;Doug Lea&lt;/i&gt; (смотрите &lt;i&gt;java.util.concurrent.Exchanger.createSlot()&lt;/i&gt;): когда заканчивается память, которая нитка резервирует под молодое поколение (&lt;i&gt;TLAB&lt;/i&gt;), приходится идти в большую кучу и брать ещё немного этих вкусных кусочков памяти, что, сделать без блокировок, &lt;i&gt;CAS&lt;/i&gt;&#39;ов не удастся.&lt;br /&gt;
&lt;br /&gt;
Впрочем, что побочные эффекты при рождении и смерти объекта гарантированы каждому объекту и это касается далеко не только &lt;i&gt;autoboxing&lt;/i&gt;, просто используя &lt;i&gt;autoboxing&lt;/i&gt; вы это делаете неявно и в больших объёмах.&lt;br /&gt;
&lt;br /&gt;
Но не стоит впадать в солипсизм - придерживайтесь здравого смысла - если использование &lt;i&gt;autoboxing&lt;/i&gt; незначительное или вы используете значения из кэша значений -128 .. 127, то не стоит бросаться с топором и изничтожать его.&lt;br /&gt;
&lt;br /&gt;
Если необходимы коллекции (в т.ч. и ассоциативные массивы) с использованием примитивов - &lt;a href=&quot;http://trove.starlight-systems.com/&quot;&gt;Trove Collections&lt;/a&gt; - отличное решение, но стоит учитывать, что это не &lt;i&gt;thread safe&lt;/i&gt; коллекции. Даже если вам не нужны коллекции с примитивами, всё равно стоит взглянуть на данный &lt;i&gt;framework&lt;/i&gt; и некоторые детали реализации - &lt;a href=&quot;http://en.wikipedia.org/wiki/Open_addressing&quot;&gt;open addressing&lt;/a&gt;, hashing strategies, особенно кто не слушал курсов по &lt;i&gt;cs&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;wrappers или объекты-обёртки&lt;/h4&gt;Пожалуй я даже почти забыл об этом, но давеча кандидат на интервью буквально расковырял мою старую фобию - wrapperовофию! &lt;br /&gt;
Крайне нелепо плодить фантики-обёртки (и выкидывать) на критически важном (с точки зрения производительности) пути выполнения. &lt;br /&gt;
&lt;br /&gt;
Словом, используя &lt;i&gt;шаблоны проектирования&lt;/i&gt; включайте голову и ощущайте &lt;a href=&quot;http://www.amazon.com/Bitter-Java-Bruce-Tate/dp/193011043X&quot;&gt;горький вкус&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;String.format или MessageFormat.format&lt;/h4&gt;&lt;br /&gt;
StringBuilder/StringBuffer в методах &lt;i&gt;append&lt;/i&gt; использует default visibility методы на уровне пакета &lt;i&gt;java.lang&lt;/i&gt;, такие как &lt;i&gt;Integer.getChars(int value, int posAtBuf, char[] buf)&lt;/i&gt;, которые дают возможность прямого добавления строкового представления числа в &lt;i&gt;char[]&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Для наглядности,&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;final String s = String.format(&quot;value is %d&quot;, ( 100000L + v) );&lt;/code&gt;&lt;/pre&gt;что творится внутри в деталях пообъектно:&lt;pre class=&quot;code&quot;&gt;allocated the object 
 of type java/nio/HeapCharBuffer whose size is 48

an array of java.lang.Object[1]
allocated the object 100009 of type java/lang/Long whose size is 16
an array of char[16]
allocated the object  of type java/lang/StringBuilder whose size is 16
an array of char[18]
allocated the object RU of type java/lang/StringBuffer whose size is 16
an array of char[3]
allocated the string &#39;RUB&#39;
allocated the object java.text.DecimalFormatSymbols@117fc of type java/text/DecimalFormatSymbols whose size is 64
allocated the object  of type java/util/Formatter whose size is 24
an array of java.lang.Object[10]
allocated the object [] of type java/util/ArrayList whose size is 24
allocated the string &#39;value is &#39;
allocated the string &#39;value is &#39;
allocated the object value is  of type java/util/Formatter$FixedString whose size is 16
an array of java.lang.String[6]
allocated the string &#39;&#39;
allocated the string &#39;d&#39;
an array of char[0]
allocated the object  of type java/util/Formatter$Flags whose size is 16
an array of java.util.Formatter$Flags[1]
allocated the object d of type java/util/Formatter$FormatSpecifier whose size is 40
an array of java.util.Formatter$FormatString[0]
an array of char[32]
allocated the string &#39;java/util/Formatter$FormatString&#39;
an array of java.util.Formatter$FormatString[2]
an array of char[16]
allocated the object  of type java/lang/StringBuilder whose size is 16
an array of char[6]
allocated the string &#39;100009&#39;
an array of char[6]
an array of char[6]
allocated the string &#39;100009&#39;
an array of char[15]
allocated the string &#39;value is 100009&#39;
String.format &lt;b&gt;count:35 size:1016&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;
против&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;final String s = &quot;value is &quot; + (100000L + v);&lt;/code&gt;&lt;/pre&gt;и его детали пообъектно:&lt;pre class=&quot;code&quot;&gt;an array of char[25]
allocated the object value is  of type java/lang/StringBuilder whose size is 16
an array of char[15]
allocated the string &#39;value is 100009&#39;
StringBuilder &lt;b&gt;count:4 size:152&lt;/b&gt;
&lt;/pre&gt;&lt;br /&gt;
Словом, чего только нет в &lt;b&gt;String.format&lt;/b&gt; - и уж сильно сомневаюсь, что escape анализ тут как-то поможет, в то же время как в случае неявного &lt;i&gt;StringBuilder&lt;/i&gt; он может помочь избавив от одной аллокации массива (и копирования).&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;immutability&lt;/h4&gt;&lt;br /&gt;
При всех своих плюсах &lt;i&gt;immutability&lt;/i&gt; (нет необходимости в явных барьерах памяти, защищённость объекта и т.п.) не совместим с &lt;i&gt;garbage less&lt;/i&gt; настолько, что добавить больше нечего.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Использовать с опаской&lt;/h2&gt;&lt;br /&gt;
&lt;h4&gt;LinkedList&lt;/h4&gt;&lt;br /&gt;
Стоит определится, что данная структура имеет скорее больше минусов, чем плюсов (по сравнению с &lt;i&gt;ArrayList&lt;/i&gt;) - сложность поиска элемента по индексу &lt;i&gt;O(N)&lt;/i&gt;, дополнительные расходы по памяти и кроме того больше живых нод для &lt;i&gt;gc&lt;/i&gt;, и как следствие, замедление его работы. &lt;br /&gt;
&lt;br /&gt;
И пожалуй единственное разумное использование данной реализации списка, когда необходимо &lt;b&gt;часто&lt;/b&gt; изменять - удалять или вставлять, элементы не в конец списка. &lt;br /&gt;
&lt;br /&gt;
Кроме всего прочего, если сравнить подобные операции с &lt;i&gt;ArrayList&lt;/i&gt; - то далеко не всегда удаление элемента даже из начала будет проигрышным для &lt;i&gt;ArrayList&lt;/i&gt; - прежде всего из-за нелинейности при копировании памяти.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Улучшения&lt;/h2&gt;&lt;br /&gt;
&lt;h4&gt;CopyOnWriteArrayList&lt;/h4&gt;При использовании шаблона &lt;a href=&quot;http://en.wikipedia.org/wiki/Observer_pattern&quot;&gt;observer&lt;/a&gt;, для многопоточного приложения, как правило, хранят список подписчиков в &lt;i&gt;java.util.concurrent.CopyOnWriteArrayList&lt;/i&gt;, при разумном условии, что изменение списка происходит существенно реже, чем уведомление о событии.&lt;br /&gt;
&lt;br /&gt;
При обходе списка будет создан &lt;i&gt;java.util.Iterator&lt;/i&gt;, который за свою короткую жизнь, успевает немного, но подгадить, особенно, если с учётом объёма потока сообщений.&lt;br /&gt;
&lt;br /&gt;
Избежать это можно, если пойти на компромисс - нарушение безопасности в обмен на чистоту (garbage free):&lt;br /&gt;
&lt;br /&gt;
Используемый нами &lt;i&gt;CopyOnWriteArrayList&lt;/i&gt; отличается от базового &lt;i&gt;java.util.concurrent.CopyOnWriteArrayList&lt;/i&gt; наличием метода&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;/**
 * read-only access method
 */
public V[] getArray(){
    return array;
}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Т.о. мы понимаем, что получаем ссылку потокобезопасно на массив (и его элементы) и могли бы творить всё, что угодно, но контракт приписывает использовать его только для чтения.&lt;br /&gt;
&lt;br /&gt;
Сторонники Escape Анализа могут поспорить, но &lt;i&gt;какие ваши доказательства ?&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
Тем же, &lt;s&gt;у кого руки в крови&lt;/s&gt; кто аргументирует коротким временем жизни &lt;i&gt;итератора&lt;/i&gt; - простая модификация с хорошим профитом.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;ConcurrentLongObjectHashMap&lt;/h4&gt;&lt;br /&gt;
Вполне очевидно, что одного &lt;i&gt;Trove Collections&lt;/i&gt; для жизни мало, особенно, когда идёт речь о конкурентной среде. &lt;br /&gt;
&lt;br /&gt;
Писать свой целый &lt;i&gt;thread safe&lt;/i&gt; вариант для всех типов и видов коллекций не было&lt;br /&gt;
ни цели, ни желания, ни тем более времени.&lt;br /&gt;
&lt;br /&gt;
В итоге на базе &lt;i&gt;java.util.concurrent.ConcurrentHashMap&lt;/i&gt; появился ассоциативный список с &lt;i&gt;long&lt;/i&gt;&#39;ами в качестве ключей. &lt;br /&gt;
&lt;br /&gt;
Оставим это упражнение для самостоятельного изучения читателю.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;blobs&lt;/h4&gt;&lt;br /&gt;
Существует не малый ряд задач, когда надо хранить большие объёмы (GBs) информации , которые надо просто отправлять в поток (&lt;i&gt;stream&lt;/i&gt;) т.е. по-сути &lt;i&gt;блобы&lt;/i&gt;. Соображение простое - объёмы данных таковы, что можно целиком (или почти целиком) загрузить в оперативную память, тем более, что она всё более и более доступна. &lt;br /&gt;
&lt;br /&gt;
Типичные примеры - фото в социальных сетях, реплики данных в кластерах (hazelcast, terracota) и т.п.&lt;br /&gt;
&lt;br /&gt;
Очевидно, что хранить каждое фото в виде отдельного объекта, пусть даже массива байт, накладно, когда таких объектов становится несколько миллионов прежде всего потому, как обход такого графа gc может занять существенное время, что приводит к отказу сервиса на некоторое время. &lt;br /&gt;
&lt;br /&gt;
Тот самый случай, когда большой размер кучи враждует с &lt;i&gt;garbage collector&lt;/i&gt;&#39;ом. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Blob&lt;/i&gt; хранилище, как правило, располагают в off-heap - т.е один большой кусок памяти, за спиной у &lt;i&gt;gc&lt;/i&gt;, над которым производят &lt;i&gt;ручное&lt;/i&gt; управление памятью (custom memory mngmt).&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Anything else ?&lt;/i&gt;</description><link>http://dolzhenko.blogspot.com/2012/11/garbage-less.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6846943764289788826</guid><pubDate>Wed, 31 Oct 2012 12:37:00 +0000</pubDate><atom:updated>2012-11-03T22:57:48.269+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">paragliding</category><category domain="http://www.blogger.com/atom/ns#">парадром</category><title>Paragliding: U-Turn Blacklight</title><description>Добрых шесть лет верой и правдой служил мне мой крыл - триколор U-Turn &lt;b&gt;Infinity II&lt;/b&gt;. Где мы только с ним не побывали, в каких &lt;s&gt;жо&lt;/s&gt;условиях не бывали, но его время пришло. Тем более, что летом на Юце имелась чудесная возможность немного попробовать &lt;a href=&quot;http://www.u-turn.de/site/index.php?id=198&amp;L=1&quot;&gt;&lt;b&gt;U-Turn Blacklight&lt;/b&gt;&lt;/a&gt; (удлинение 5.8, качество 10.5) - и надо сказать, что его скорость просто впечатлила . Вполне очевидно, что драгдиллер сделал предложение от которого я не смог удержаться - и крыл был заказан.&lt;br /&gt;
&lt;br /&gt;
Ранее уже опробовал &lt;b&gt;obsession&lt;/b&gt; - как в динамике, так и в термичке. Надо сказать, что первый полёт мне больше всего запомнился, и прежде всего хлопаньем &lt;i&gt;ушей&lt;/i&gt;, что впрочем никак не отражалось на безопасности или управляемости крыла. &lt;br /&gt;
&lt;br /&gt;
И вот настал долгожданный момент - пришёл мой крыл в желаемой &lt;i&gt;не серийной&lt;/i&gt; расцветке&lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;img src=&quot;http://distilleryimage7.s3.amazonaws.com/b6d9c878108011e2bb0f22000a1cfde9_7.jpg&quot;/&gt;&lt;br /&gt;
lime/black/white&lt;/div&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
За окном октябрь и погода явно не собиралась становится лётной, ехать на &lt;i&gt;SIV&lt;/i&gt; было и слишком поздно с одной стороны, и немного стрёмно с другой - с новым крылом и сразу на &lt;i&gt;SIV&lt;/i&gt; ... &lt;br /&gt;
&lt;br /&gt;
Как бы случайно, получается поехать в Крым - и хорошо складывается - погода +25С, вода +22С, прогноз на три лётных дня и взять на работе отпуск менее, чем за неделю&lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;a href=&quot;https://twitter.com/dolzhenko/status/257782600851148800/photo/1&quot;&gt;&lt;img src=&quot;https://pbs.twimg.com/media/A5PT6OFCUAArrmw.jpg&quot; border=&quot;0&quot;/&gt;&lt;br /&gt;
коктебель.погода.шикарно.&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Старт вблизи погранзаставы, ровный бриз 3-4 м/с - идеальные условия, чтобы немного позаниматься &lt;i&gt;наземкой&lt;/i&gt; с новым для меня крылом. Определённо это не infinity, здесь более плавно и аккуратно надо, словом чем-то похож на obsession, крыло отзывчиво, замечательно управляется весом (подвеска &lt;i&gt;Skyline Pure&lt;/i&gt;). &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;img src=&quot;http://dolzhenko.softlogic.ru/8678l.jpg&quot; border=&quot;0&quot;/&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Замечание&lt;/i&gt;&lt;/b&gt;: я не являюсь ни тест-пилотом, ни с претензией на тест-пилота, полноту описания и/или испытаний, я только описываю свои ощущения.&lt;br /&gt;
&lt;br /&gt;
Буквально перед вылетом в Крым наши братья-пилоты из Новороссийска тоже получили &lt;i&gt;Blacklight&lt;/i&gt; и опробовали его. Однако, они нашли его &lt;i&gt;диким мустангом&lt;/i&gt;, что надо сказать немного меня фрустировало. &lt;br /&gt;
&lt;br /&gt;
Словом, полный скепсиса я походил с ним взад-вперёд, слетел метров 10 по склону, сделал полгалса, потом галс, вернулся на исходную точку старта. Какой ещё дикий? какой мустанг ? &lt;br /&gt;
Тем временем ветер немного усилился и стало поддерживать, стали подтягиваться местные пилоты. &lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;img src=&quot;http://dolzhenko.softlogic.ru/8705l.jpg&quot; border=&quot;0&quot;/&gt;&lt;/div&gt;&lt;br /&gt;
Первое, очень непривычное ощущение - заметно высокая скорость - даже в слабый ветер я не помню, чтобы с такой скоростью шёл вдоль склона на &lt;i&gt;infinity&lt;/i&gt;, думал, что ошибся с направлением ветра, однако, при проходе другим галсом скорость была ещё выше - не ошибся, подумал Штирлиц. Посадка на склон не простит наглости - если по касательной, то хорошо затормозить купол.&lt;br /&gt;
&lt;br /&gt;
Первый лётный день прошёл в знакомстве с куполом - управление весом - отзывчивое, без заметных пауз в реакции, при этом не болтает из стороны в сторону. Клевантами так же управляется без задержек. &lt;br /&gt;
&lt;br /&gt;
На следующий день ровный бриз с моря 7-8 м/с, решил немного расширить зону полётов - стал забирать влево от старта почти на км, буквально 100 метров не доходя до мысочка (см. карту ниже). &lt;br /&gt;
&lt;br /&gt;
Но давайте чуть отвлечёмся и перенесёмся немного в прошлое слегка в другой район - в июль этого года на гору Юцу ...&lt;br /&gt;
Одним июльским утром на склоне Малёв сказал, что хватит ! Суть упражнения: поднять крыло, удерживая его в воздухе простоять в очереди к сан сею, подойти к нему (всё так же удерживая крыло в воздухе), встать на указанное им место - например, камень почёта, выслушать инструкцию к полёту - и только после этого он разрешает оторваться и взлететь. &lt;br /&gt;
И вот в очередной раз подхожу к сансею и ... роняю купол на землю. Месье негодует: &lt;i&gt;&amp;laquo;Двоечник! Вон отсюда! &amp;raquo;&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Но всё же вернёмся на каменистые склоны Крыма - поднимаю я свой новенький крыл, но слишком резко, так, что ветер его выдёргивает, а я не успеваю его притормозить, роняю на землю - и словно хлопок по ушам &lt;i&gt;&amp;laquo;Двоечник! Вон отсюда! &amp;raquo;&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Не смотря на то, что некоторые местные пилоты имеют тенденцию грузить купола по верхней границе, мы шли с ними примерно на равных скоростях, тогда как я гружу купол чуть ниже середины вилки (75 + 18 кг на крыле с вилкой 85-110 кг). &lt;br /&gt;
При этом когда ветер усиливался и многие начинали висеть поплавками я продолжать летать и свободно пробиваться вперёд.&lt;br /&gt;
&lt;br /&gt;
Сделал &lt;i&gt;wingover&lt;/i&gt;&#39;ы - понравилась динамика, но не стал злоупотреблять и делать глубокие wingover&#39;ы. При выходе вполне ожидаемо хочет вырваться. &lt;br /&gt;
&lt;br /&gt;
В полевых условиях подвязал акселератор - чуть слабее, чем можно было бы. Лучше не довязать, чем перевязать. Наполовину вытопленный аксель даёт небольшое, но всё же заметное (на глаз) ускорение, при этом, какого-либо просаживания по высоте не заметил, скорее тут заслуга бриза. Другое же дело, когда я вытопил акселератор на всю - ветер начинал свистеть о свободные концы и шлем - gps не брал и не замерял прирост скорости - оценочно +20км/ч. &lt;br /&gt;
&lt;br /&gt;
Порой раздувало так, что вперёд переставал пробиваться. Стал искать крайние стропы первого ряда, чтобы сделать &lt;i&gt;большие уши&lt;/i&gt;, и если на &lt;i&gt;infinity&lt;/i&gt; это были просто крайняя стропа &lt;b&gt;A&lt;/b&gt;(первого) ряда, которая для удобства окрашивалась в другой цвет, на &lt;i&gt;blacklight&lt;/i&gt; для этого выведен специальный &lt;b&gt;A1&lt;/b&gt; или ушной ряд. При этом как-то смущало, что стропы &lt;b&gt;A&lt;/b&gt;(первого) ряда уходят вверх к примерно к 60% длины передней кромки. &lt;i&gt;&amp;laquo;А не сделаю ли я ушами фронталочку ?&lt;/i&gt;&amp;raquo; Сложил, но немного, полёт нормальный, весом рулится уверенно. Обратно уши сами не разлипают, надо их расхлопывать, немного прокачав клевантами.&lt;br /&gt;
&lt;br /&gt;
p.s. конечно же для полноты ощущений купол надо облётывать в термичке, полёты в ровном динамике на бризе позволили мне спокойно познакомиться с крылом, немного привыкнуть к нему и его скорости. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;center&quot;&gt;&lt;img src=&quot;http://distilleryimage5.s3.amazonaws.com/c47046501abd11e28ad722000a9f1498_7.jpg&quot;/&gt;&lt;br /&gt;
Осень в Крыму сказочна красива&lt;/div&gt;&lt;br /&gt;
&lt;iframe width=&quot;600&quot; height=&quot;400&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; src=&quot;https://maps.google.com/?ie=UTF8&amp;amp;ll=44.969216,35.27828&amp;amp;spn=0.011796,0.018904&amp;amp;t=h&amp;amp;z=16&amp;amp;output=embed&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
ветер: Ю, Ю-В&lt;br /&gt;
точка старта:&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;N&lt;/span&gt; 44&lt;sup&gt;o&lt;/sup&gt; 58.232&#39;&lt;br /&gt;
&lt;span style=&quot;font-weight: bold;&quot;&gt;E&lt;/span&gt; 035&lt;sup&gt;o&lt;/sup&gt; 16.613</description><link>http://dolzhenko.blogspot.com/2012/10/blacklight.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total><georss:featurename>Коктебель, Крым, Украина</georss:featurename><georss:point>44.96 35.2405556</georss:point><georss:box>44.9375285 35.2010736 44.9824715 35.2800376</georss:box></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-617205113934770807</guid><pubDate>Tue, 09 Oct 2012 07:00:00 +0000</pubDate><atom:updated>2012-11-13T09:00:44.577+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задача №377</title><description>&lt;div class=&quot;quote&quot;&gt;&lt;img src=&quot;http://www.getenglishlessons.com/wp-content/uploads/2011/12/Ice_Age1-300x225.jpg&quot; style=&quot;float:left;padding:10px;&quot; /&gt; Задача №&lt;b&gt;377&lt;/b&gt;:&lt;br /&gt;
&lt;br /&gt;
Белка массой 0.5 кг сидит на абсолютно гладкой, обледенелой, горизонтальной, плоской крыше. Человек бросает белке камень массой 0.1 кг. Камень летит горизонтально со скоростью 6 м/с. Белка хватает камень и удерживает его. &lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;Вычислите скорость белки, поймавшей камень.&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;внимание!&lt;/span&gt;  комментарии содержат ответ.</description><link>http://dolzhenko.blogspot.com/2012/10/377.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-1194743103735413927</guid><pubDate>Mon, 01 Oct 2012 19:22:00 +0000</pubDate><atom:updated>2012-10-11T13:38:21.011+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачка: Объём луж</title><description>&lt;div class=&quot;quote&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheL6kpgPp5WeEAHtmbzkpYvmTt-XpW8LlvY0bqmIj4cjE3B3xZP6ll6hAWR4Qo6Un_3l7scAtNAT-1Wz-1Jv3cESFtzVZm0dhb-yfKGQFcuoJ6TNCG19nnxLcGoE7RaJKCRxiF-kKrOZ4/s200/landscape.png&quot; style=&quot;float:left;padding:10px;&quot;&gt; На рельеф некоторой местности падает дождь, попадая в низменности он образует лужи и озерца. &lt;br /&gt;
&lt;br /&gt;
Найти объём образовавшихся луж за время &lt;b&gt;O(N)&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;замечание №1&lt;/i&gt;: силами поверхностного натяжения пренебречь.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;замечание №2&lt;/i&gt;: рельеф задан целыми числами&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;например&lt;/i&gt;: &lt;br /&gt;
&lt;b&gt;&lt;i&gt;V(&lt;/i&gt;&lt;/b&gt;[0, 0, 3, 6, 6, 10, 5, 5, 5, 7, 7, 4, 9, 9, 13, 12, 14, 4, 3, 0]&lt;b&gt;&lt;i&gt;)&lt;/i&gt;&lt;/b&gt; = 30.&lt;br /&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://dolzhenko.blogspot.com/2012/10/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheL6kpgPp5WeEAHtmbzkpYvmTt-XpW8LlvY0bqmIj4cjE3B3xZP6ll6hAWR4Qo6Un_3l7scAtNAT-1Wz-1Jv3cESFtzVZm0dhb-yfKGQFcuoJ6TNCG19nnxLcGoE7RaJKCRxiF-kKrOZ4/s72-c/landscape.png" height="72" width="72"/><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-3477794919850084660</guid><pubDate>Wed, 19 Sep 2012 20:37:00 +0000</pubDate><atom:updated>2012-11-14T01:10:07.690+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">garbage</category><category domain="http://www.blogger.com/atom/ns#">gc</category><category domain="http://www.blogger.com/atom/ns#">gflogger</category><category domain="http://www.blogger.com/atom/ns#">java</category><title>gflogger 0.0.9.x</title><description>&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSDsfbRk_Zh-uqy85z3wAtcIaahC9XTeOMTKbTj1OTPQWZHxTRt0ca276L516vHKcY_OxPXO-NMei67E7pj0rtXu7lwx0ggVm0GEBJFwU43JpIIj77I7MPzxW09FcrODG9SypmgDeXcxc/s225/recycling_m.png&quot;  style=&quot;display: block; float: left; margin: 20px 20px 20px 0;&quot;/&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://bitbucket.org/vladimir.dolzhenko/gflogger/&quot;&gt;&lt;i&gt;Garbage Free Logger&lt;/i&gt;&lt;/a&gt; добрался до версии 0.0.9.x . &lt;br /&gt;
&lt;br /&gt;
Надо сказать, что версия полна изменениями, допиливаниями и добавлением мелких, но важных мелочей, которые активно используются.&lt;br /&gt;
&lt;br /&gt;
Но обо всём по порядку.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Но всё же, стоит, пожалуй, начать рассказом о специфике нашего приложения: по сути это обработка потока, очень чувствительное к задержкам, работающее на куче в 1Gb - больше нам не надо, подтвеждено тестами и лучшими стоматологами. Впрочем те же тесты под хорошей нагрузкой (выше среднего) показали, что &lt;i&gt;full gc collection&lt;/i&gt; у нас не случается, а длительность суммарного &lt;i&gt;minor gc collection&lt;/i&gt; не выше 20 мс. &lt;br /&gt;
&lt;br /&gt;
Как это почти всегда водится, идея &lt;i&gt;gflogger&lt;/i&gt;&#39;а возникла утром на работе за чашечкой кофе - &lt;i&gt;Евгений Т.&lt;/i&gt; предложил использовать &lt;i&gt;off heap&lt;/i&gt; память ( волшебный камень &lt;b&gt;no. 1&lt;/b&gt; ) для &lt;i&gt;logging&lt;/i&gt;&#39;а, поскольку наше ключевое приложение пишет немало логов и существовало понимание того, что неявно, через сборщик мусора, это влияет на приложение. Т.о. хотелось получить &lt;i&gt;garbage less&lt;/i&gt; логгер.&lt;br /&gt;
&lt;br /&gt;
Сказано - сделано: вечером того же дня был написан прототип. Параллельно возникла идея сделать не &lt;i&gt;garbage less&lt;/i&gt;, а &lt;i&gt;garbage free&lt;/i&gt; т.е с волшебным свойством &lt;b&gt;Zero Object Delivery&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Дабы быть честным, отмечу, что если быть педантом, то нельзя сказать, что это &lt;b&gt;garbage free&lt;/b&gt; в полном смысле этого слова т.к. есть фаза запуска, когда мусор некоторый создаётся. Однако в стационарной фазе, без нарушения контракта использования (об ограничениях чуть позже), он действительно &lt;b&gt;garbage free&lt;/b&gt;, что более чем применимо в условиях нашего приложения.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Уточнение от &lt;a href=&quot;http://vanillajava.blogspot.com/&quot;&gt;Peter Lawrey&lt;/a&gt;: лучше говорить, не что &lt;i&gt;мы не создаём объектов&lt;/i&gt;, а что мы &lt;i&gt;их не выбрасываем&lt;/i&gt;. Т.е создаём объекты, но переиспользуем их неоднократно.&lt;br /&gt;
&lt;br /&gt;
К этому моменту уже случился &lt;i&gt;disruptor hype&lt;/i&gt;, так, что &lt;a href=&quot;http://code.google.com/p/disruptor/&quot;&gt;&lt;i&gt;disruptor&lt;/i&gt;&lt;/a&gt; как нельзя лучше подошёл и стал компонентом &lt;b&gt;no. 2&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Как только появился прототип встала проблема тестирования как уровня мусора, производительности (в сравнении с конкурентами типа &lt;i&gt;log4j&lt;/i&gt; и &lt;i&gt;logback&lt;/i&gt;), так доказательство того, что это действительно &lt;i&gt;garbage free&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Другой герой, притаившийся за кулисами, &lt;b&gt;no. 0&lt;/b&gt;: &lt;a href=&quot;http://code.google.com/p/java-allocation-instrumenter/&quot;&gt;java-allocation-instrumenter&lt;/a&gt; - java агент отслеживающий точки создания новых объектов - является очень важным для всего &lt;i&gt;gflogger&lt;/i&gt;, хотя дальше чем тесты и &lt;i&gt;benchmark&lt;/i&gt;&#39;и он не выходит. &lt;br /&gt;
&lt;br /&gt;
Пример использования &lt;i&gt;gflogger&lt;/i&gt;:&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;log.info().
    append(&quot;property named &#39;&quot;).
    append(name).
    append(&quot;&#39; has value &quot;).
    append(value).
  commit();&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;i&gt;Много было идей как называть методы: были идеи использовать &lt;b&gt;a(...)&lt;/b&gt; как append(), а &lt;b&gt;z()&lt;/b&gt; как commit(), обыгрывая идею &amp;laquo;от начала и до конца&amp;raquo; (a-z). Предлагался и православный вариант с &lt;b&gt;amen()&lt;/b&gt; вместо commit(), но всё же осталось то, что осталось.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Изначально в дизайн логгера было заложено множество вполне разумных ограничений, таких, например, как ограниченная максимальная длина сообщения. Это связано прежде всего с тем, что память резервируется заранее. Также предполагалось, что данный логгер будет использоваться бок о бок с другими логгерами (&lt;i&gt;log4j&lt;/i&gt;), которые будут использоваться в менее latency критических блоках. Т.е. с самого начала предполагалось, что это не будет ни в коем случае никакой не убийца &lt;i&gt;log4j&lt;/i&gt;, &lt;i&gt;logback&lt;/i&gt; или что вы там ещё любите, а вполне себе такой &lt;i&gt;ad hoc&lt;/i&gt; для чувствительных к latency местах. &lt;br /&gt;
&lt;br /&gt;
Ни о каком удобстве конфигурации через xml файлы, не тем более о иерархии категорий. &lt;br /&gt;
&lt;br /&gt;
Казалось бы вон оно счастье, близко за не укусишь. Душа просит цифр и фактов. Первый же &lt;i&gt;benchmark&lt;/i&gt;, написанный по всем законам жанра - с прогревом как у реактивного самолёта, всё как положено и ... осечка - почти линейная зависимость по времени работы &lt;i&gt;gc&lt;/i&gt; от количества сообщений. &lt;br /&gt;
&lt;br /&gt;
Что-то явно где-то подтекает. &lt;br /&gt;
&lt;br /&gt;
Тут небольшая ремарка - &lt;i&gt;gflogger&lt;/i&gt; поддерживает шаблоны сообщений близкие к синтаксису &lt;i&gt;log4j&lt;/i&gt;. Кстати, многие зря хоронят рабочую лошадку.&lt;br /&gt;
&lt;br /&gt;
Но вернёмся же к нашим &lt;s&gt;баран&lt;/s&gt; шаблонам: мы обычно используем, кроме самого сообщения ещё и метку времени, имя категории (класса или его части), а так же имя нити из которой было отправлено сообщение. &lt;br /&gt;
&lt;br /&gt;
Моему удивлению не было предела: &amp;laquo;мусорил&amp;raquo; метод &lt;i&gt;thread.getName()&lt;/i&gt;. Впрочем, автор &lt;i&gt;java.lang.Thread&lt;/i&gt; в &lt;i&gt;jdk&lt;/i&gt; пожелал остаться неизвестным (&lt;i&gt;unascribed&lt;/i&gt;), канул в лета за давностью лет.&lt;br /&gt;
&lt;br /&gt;
Первые версии, которые, однако, никак не помечались в репозитории ( просто публиковались в локальный ivy репозиторий ), страдали многими детскими болезнями, такими как переинициализация, и моя коллега &lt;i&gt;Юля В.&lt;/i&gt;, ныне работающая в g**g*e, стала первой кто начал обкатывать &lt;i&gt;gflogger&lt;/i&gt;. Так оно жило до версии &lt;i&gt;0.0.6&lt;/i&gt; . &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В апреле случился &lt;i&gt;Moscow Oracle Developer Day&lt;/i&gt; он же бывший &lt;i&gt;Java One Days&lt;/i&gt;, на котором делал доклад о &lt;i&gt;gflogger&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
За день до &lt;i&gt;Moscow Oracle Developer Day&lt;/i&gt; случилось то, что должно было случиться : &lt;a href=&quot;https://bitbucket.org/vladimir.dolzhenko/gflogger/&quot;&gt;репозиторий&lt;/a&gt; был переведён из приватного в публичный, а версия &lt;i&gt;0.0.6&lt;/i&gt; первая публичная версия под &lt;i&gt;Apache license&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
Впрочем, там же случилось и другое событие - таки встретил лично и пообщался в живую с &lt;a href=&quot;http://cheremin.blogspot.com/&quot;&gt;&lt;i&gt;Русланом Ч.&lt;/i&gt;&lt;/a&gt;, который сделал, как не только я считаю, отличнейший доклад о том как он, молодой и красивый, со скальпелем в руках препарировал &lt;i&gt;disruptor&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Так почему же это &lt;i&gt;open source&lt;/i&gt; ? &lt;br /&gt;
&lt;br /&gt;
Прежде всего это моя любовь к &lt;i&gt;open source&lt;/i&gt; движению в целом. Во вторых все используемые базовые компоненты или честно экспроприированный код - это тоже &lt;i&gt;open source&lt;/i&gt; открытые под &lt;i&gt;apache license&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
Но это всё то, что лежит на поверхности и слишком очевидно. Другая сторона заключена в том, что это своего рода реклама работодателя. &lt;br /&gt;
Первый же вопрос, который мне задали на  &lt;i&gt;Moscow Oracle Developer Day&lt;/i&gt; звучал примерно так: &lt;i&gt;&amp;laquo;Чем вы занимаетесь, что для Вас суммарный stop-the-world в 30 ms это время ?&amp;raquo;&lt;/i&gt;. А ещё, &lt;s&gt;а у нас, а мы, а я&lt;/s&gt; мы занимаемся много чем другим полезным и интересным.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Но всё же, вернёмся с фенечкам, бортикам и прочим рюшечкам.&lt;br /&gt;
&lt;br /&gt;
Ещё одной, немного запоздалой идеей стало использование однобайтового представления символа (&lt;i&gt;char&lt;/i&gt;): как известно, в &lt;i&gt;java&lt;/i&gt; представление &lt;i&gt;char&lt;/i&gt; базируется на стандарте &lt;i&gt;unicode&lt;/i&gt;, и поэтому занимает 2 байта. &lt;br /&gt;
Начиная с java6u21 можно использовать флаг &lt;i&gt;-XX:+UseCompressedStrings&lt;/i&gt;, это позволяет &lt;i&gt;java.lang.String&lt;/i&gt; использовать массив байт вместо массива символов (&lt;i&gt;char&lt;/i&gt;). &lt;br /&gt;
&lt;br /&gt;
Разумно было включить однобайтный режим по-умолчанию, особенно учитывая, что все наши сообщения на английском языке. Результаты тестов показали то, что и ожидалось: производительность почти в 2 раза выше, чем в многобайтном режиме.&lt;br /&gt;
&lt;br /&gt;
Дальше - больше. &lt;i&gt;Harald W.&lt;/i&gt;, решает использовать &lt;i&gt;gflogger&lt;/i&gt; в проекте, который только только должен пойти в live. И что самое удивительное как &lt;i&gt;general purpose logger&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
Тем самым был задан не просто толчок, а хороший &lt;s&gt;пинок&lt;/s&gt; вектор развития. &lt;br /&gt;
&lt;br /&gt;
Где бы я ещё мог увидеть начальника так лихо линчующего &lt;s&gt;го&lt;/s&gt;код ? Между делом &lt;i&gt;Harald W.&lt;/i&gt; влил в кодовую базу настройщик из &lt;i&gt;xml&lt;/i&gt; файла. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Дмитрий Г.&lt;/i&gt; не раз натыкался на краевые моменты - забыл закоммитить сообщение, но не понятно откуда это произошло. Или форматирование исключений немного не православное и среда разработки не помогает автоматично перескочить на нужную строчку кода. Словом даёшь валидацию и человеческое &lt;s&gt;мор&lt;/s&gt;лицо. &lt;br /&gt;
&lt;br /&gt;
Руслан, надкусывая шоколадку и в очередной раз радуясь &lt;i&gt;google guava&lt;/i&gt;, захотел ещё больше сладкого - и теперь можно использовать шаблоны форматирования в сообщении. Словом, как-то так:&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;code class=&quot;java&quot;&gt;log.info(&quot;property named &#39;%s&#39; has value %s&quot;).
    with(name).
    withLast(value);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Ещё одной хорошей идеей от Руслана стали форматировщики объектов: раньше, если добавить через &lt;i&gt;append()&lt;/i&gt; некоторый объект, то он по факту, будет добавлен через метод &lt;i&gt;toString()&lt;/i&gt;, что приводит к мусору. В то же время, завязывать свои доменные объекты на gflogger через интерфейс &lt;i&gt;Loggable&lt;/i&gt; можно, но не хочется. Регистрируя &lt;i&gt;ObjectFormatter&lt;/i&gt; можно задавать отображение некоторого класса в &lt;i&gt;gflogger&lt;/i&gt; представление.&lt;br /&gt;
&lt;br /&gt;
И в заключение - мои коллеги по команде в том или ином виде вносят вклад в дело &lt;i&gt;gflogger&lt;/i&gt;: кто отличными идеями, кто практической обкаткой кода и замечаниями по улучшению, кто-то внесением правок в кодовую базу, ломая тем самым исходные ограничения, но оставаясь &lt;i&gt;garbage free&lt;/i&gt;. &lt;br /&gt;
&lt;br /&gt;
Тем временем на подходе версия 0.1.0, с шахматами, поэтессами, и всём тем, что уже есть в 0.0.9.* .</description><link>http://dolzhenko.blogspot.com/2012/09/gflogger-009x.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSDsfbRk_Zh-uqy85z3wAtcIaahC9XTeOMTKbTj1OTPQWZHxTRt0ca276L516vHKcY_OxPXO-NMei67E7pj0rtXu7lwx0ggVm0GEBJFwU43JpIIj77I7MPzxW09FcrODG9SypmgDeXcxc/s72-c/recycling_m.png" height="72" width="72"/><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-8036910177688905844</guid><pubDate>Wed, 19 Sep 2012 17:15:00 +0000</pubDate><atom:updated>2012-11-14T01:10:15.639+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datastructures</category><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачки: Количество сообщений в минуту</title><description>&lt;div class=&quot;quote&quot;&gt;Есть некоторый поток сообщений, идущий не равномерно. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Например&lt;/i&gt;, с 0 - 10 секунду может прийти 1 сообщение, в следующие 10 ещё 5, потом 10, потом 100 и т.д и опять наступит затишье.&lt;br /&gt;
&lt;br /&gt;
В целях мониторинга хочется иметь представление о точном количестве полученных сообщений (скользящим окном) за крайнюю минуту. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Пояснение: если мы запрашиваем кол-во сообщений в 13:12:05, то должны получить кол-во сообщений с 13:11:05 по 13:12:05. Запрос в 13:12:57 отображает число сообщений с 13:11:57 по 13:12:57&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
При этом не интересует сколько было получено две минуты назад, только реальные актуальные цифры. Допускается огрубление с точностью до секунды.&lt;br /&gt;
&lt;br /&gt;
Ограничения: память O(1), сложность O(1), одна нитка выполнения.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;p.s.&lt;/span&gt; я не знаю, существует ли какое-то &lt;i&gt;классическое&lt;/i&gt; и/или единственно верное решение или нет, уже засыпая я смог придумать вполне приемлемое для меня решение, но которое расходует больше, чем 3-5 переменных.</description><link>http://dolzhenko.blogspot.com/2012/09/blog-post_19.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-4731729074853570354</guid><pubDate>Tue, 04 Sep 2012 18:37:00 +0000</pubDate><atom:updated>2012-11-14T01:10:21.028+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datastructures</category><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>Задачка: &amp;lt;L| и |R&amp;gt;</title><description>&lt;div class=&quot;quote&quot;&gt;Заданы два оператора:&lt;br /&gt;
&lt;b&gt;L&lt;/b&gt; : &lt;b&gt;L&lt;/b&gt;(a,b) =&amp;gt; ( 2 * a - b , b ) &lt;br /&gt;
&lt;b&gt;R&lt;/b&gt; : (a,b)&lt;b&gt;R&lt;/b&gt; =&amp;gt; ( a, 2 * b - a ) &lt;br /&gt;
и начальная точка (a, b) = (0, 1).&lt;br /&gt;
&lt;br /&gt;
Существует последовательность операторов &lt;b&gt;L&lt;/b&gt; и &lt;b&gt;R&lt;/b&gt;, такая, что в результате либо &lt;b&gt;a&lt;/b&gt; = &lt;b&gt;N&lt;/b&gt;, либо &lt;b&gt;b&lt;/b&gt; = &lt;b&gt;N&lt;/b&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Например&lt;/i&gt;:&lt;br /&gt;
Число &lt;b&gt;21&lt;/b&gt; может быть получено кратчайшей последовательностью &lt;b&gt;L L R L R&lt;/b&gt;:&lt;br /&gt;
&lt;span style=&quot;font-family:Courier New;&quot;&gt;&lt;i&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;(a, b):&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;L&lt;/b&gt;(a, b) | (a, b)&lt;b&gt;R&lt;/b&gt; &lt;/i&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;(0, 1):&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;(-1, 1)&lt;/b&gt; | (0, 2)&lt;br /&gt;
&amp;nbsp;(-1, 1):&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;(-3, 1)&lt;/b&gt; | (-1, 3)&lt;br /&gt;
&amp;nbsp;(-3, 1):&amp;nbsp;&amp;nbsp;&amp;nbsp;(-7, 1) | &lt;b&gt;(-3, 5)&lt;/b&gt; &lt;br /&gt;
&amp;nbsp;(-3, 5):&amp;nbsp;&amp;nbsp;&lt;b&gt;(-11, 5)&lt;/b&gt; | (-3, 13)&lt;br /&gt;
(-11, 5):&amp;nbsp;&amp;nbsp;(-27, 5) | &lt;b&gt;(-11, &lt;span style=&quot;color:red;&quot;&gt;21&lt;/span&gt;)&lt;/b&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size:1.1em;&quot;&gt;Какова минимальная длина последовательности с помощью которой можно получить &lt;b&gt;N&lt;/b&gt; ?&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Замечание №1&lt;/i&gt;: число &lt;b&gt;N&lt;/b&gt; может лежать в диапозоне -2&lt;sup&gt;31&lt;/sup&gt; .. 2&lt;sup&gt;31&lt;/sup&gt;-1.&lt;br /&gt;
&lt;i&gt;Замечание №2&lt;/i&gt;: сложность &lt;b&gt;O(log(N))&lt;/b&gt;.&lt;br /&gt;
&lt;i&gt;Замечание №3&lt;/i&gt;: досупная память &lt;b&gt;O(1)&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;внимание!&lt;/span&gt;  комментарии содержат ответ.</description><link>http://dolzhenko.blogspot.com/2012/09/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>8</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-128278034375827171</guid><pubDate>Mon, 20 Aug 2012 15:30:00 +0000</pubDate><atom:updated>2013-03-15T22:20:51.374+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">bash</category><category domain="http://www.blogger.com/atom/ns#">hints</category><title>Bash: Let me bash that for you, Part 1</title><description>Let&#39;s get the next dan of bash with the text processing.&lt;br /&gt;
&lt;br /&gt;
The 1st note is the greatest idea of the whole &lt;i&gt;unix&lt;/i&gt; is in that everything is file - classic file, directory, devices, file systems and so on. &lt;br /&gt;
&lt;br /&gt;
Many commands expects the file for its input or it could be a simple standard input &lt;i&gt;also known as&lt;/i&gt; &lt;b&gt;&lt;i&gt;stdin&lt;/i&gt;&lt;/b&gt; (refers as stream #&lt;b&gt;0&lt;/b&gt;).&lt;br /&gt;
&lt;br /&gt;
As well many commands put their output to standard output &lt;i&gt;aka&lt;/i&gt; &lt;b&gt;&lt;i&gt;stdout&lt;/i&gt;&lt;/b&gt;  (refers as stream #&lt;b&gt;1&lt;/b&gt;) or to standard error output &lt;i&gt;aka&lt;/i&gt; &lt;b&gt;&lt;i&gt;stderr&lt;/i&gt;&lt;/b&gt; (refers as stream #&lt;b&gt;2&lt;/b&gt;).&lt;br /&gt;
&lt;br /&gt;
There are several key text processing command and several techniques like stream redirection.&lt;br /&gt;
&lt;br /&gt;
And once more! the most powerful command is &lt;b&gt;man&lt;/b&gt; means &lt;b&gt;manual&lt;/b&gt;. &lt;a name=&#39;more&#39;&gt;&lt;/a&gt;If you&#39;d like to know more about some command - just type, e.g.&lt;br /&gt;
&lt;pre&gt;$ &lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?echo&quot;&gt;man echo&lt;/a&gt;
ECHO(1)    User Commands         ECHO(1)

NAME


       echo - display a line of text

&lt;/pre&gt;&lt;br /&gt;
&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?echo&quot;&gt;echo&lt;/a&gt; &lt;i&gt;message&lt;/i&gt;&lt;/b&gt;&lt;/h2&gt;as just mentioned - display a line of text&lt;br /&gt;
&lt;pre&gt;$ echo Hello
Hello
$ echo Hello world
Hello world
$ echo &quot;Hello world&quot;
Hello world&lt;/pre&gt;&lt;i&gt;&lt;b&gt;Note&lt;/b&gt;&lt;/i&gt;: &lt;i&gt;echo&lt;/i&gt; adds &lt;i&gt;newline&lt;/i&gt; character (\n) and the end of line - therefore &quot;hello&quot; costs 5 byte + 1 byte which is &lt;i&gt;newline&lt;/i&gt; character.&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Hint&lt;/b&gt;&lt;/i&gt;: echo &lt;b&gt;-n&lt;/b&gt; doesn&#39;t add the trailing newline&lt;br /&gt;
&lt;pre&gt;$ echo -n &quot;Hello world&quot;
Hello world $ &lt;/pre&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?wc&quot;&gt;wc&lt;/a&gt;&lt;/b&gt; [&lt;i&gt;option&lt;/i&gt;] [&lt;i&gt;file&lt;/i&gt;]&lt;/h2&gt;&lt;b&gt;w&lt;/b&gt;ord &lt;b&gt;c&lt;/b&gt;ounter - prints newline, word, and byte counts of file&lt;br /&gt;
&lt;pre&gt;$ wc myfile
 2  2 12 myfile&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt;option &lt;b&gt;-c&lt;/b&gt; counts bytes&lt;br /&gt;
&lt;pre&gt;$ wc -c myfile
12 myfile&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt;option &lt;b&gt;-l&lt;/b&gt; (line) counts newline&lt;br /&gt;
&lt;pre&gt;$ wc -l myfile
2 myfile&lt;/pre&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?cat&quot;&gt;cat&lt;/a&gt; &amp;nbsp; &lt;i&gt;file&lt;/i&gt;&lt;/b&gt;&lt;/h2&gt;prints out file content&lt;br /&gt;
&lt;pre&gt;$ cat myfile
Hello
world&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; there are &lt;i&gt;gzcat&lt;/i&gt; for Solaris and &lt;i&gt;zcat&lt;/i&gt; for GNU/Linux to print over gzipped file. Moreover, &lt;i&gt;gzcat&lt;/i&gt;/&lt;i&gt;zcat&lt;/i&gt; is able to handle as well gzipped files as well the ungzipped ones.&lt;br /&gt;
&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?grep&quot;&gt;grep&lt;/a&gt; [&lt;i&gt;option&lt;/i&gt;] [&lt;i&gt;pattern&lt;/i&gt;] &lt;i&gt;file&lt;/i&gt;&lt;/b&gt;&lt;/h2&gt;filters lines that case-&lt;b&gt;sensitive&lt;/b&gt; matches the pattern&lt;br /&gt;
&lt;pre&gt;$ grep He myfile
&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;He&lt;/span&gt;&lt;/b&gt;llo
$ grep z myfile
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# nothing&lt;/span&gt;&lt;/i&gt;
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt;option &lt;b&gt;-i&lt;/b&gt; filters case-&lt;b&gt;insensitive&lt;/b&gt; matching lines &lt;br /&gt;
&lt;pre&gt;$ grep he myfile
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# nothing&lt;/span&gt;&lt;/i&gt;
$ grep -i he myfile
&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;He&lt;/span&gt;&lt;/b&gt;llo&lt;/pre&gt;&lt;i&gt;&lt;b&gt;Hint&lt;/b&gt;&lt;/i&gt;:option &lt;b&gt;-v&lt;/b&gt; selects &lt;b&gt;non&lt;/b&gt;-matching lines &lt;br /&gt;
&lt;pre&gt;$ grep -v He myfile
&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;world&lt;/span&gt;&lt;/b&gt;&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt;option &lt;b&gt;-c&lt;/b&gt; counts number of matched lines&lt;br /&gt;
&lt;pre&gt;$ grep -c He myfile
1
$ grep -c he myfile
0
$ grep -ci he myfile
1
$ grep -cv z myfile
2&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; there are &lt;i&gt;gzgrep&lt;/i&gt; for Solaris and &lt;i&gt;zgrep&lt;/i&gt; for GNU/Linux to grep over gzipped file. Moreover, &lt;i&gt;gzgrep&lt;/i&gt;/&lt;i&gt;zgrep&lt;/i&gt; is able to handle as well gzipped files as well the ungzipped ones.&lt;br /&gt;
&lt;h2&gt;stream redirection&lt;/h2&gt;&lt;li&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;br /&gt;
override the file and appends to it (creates the file if not present).&lt;pre&gt;$ echo hello &amp;gt; file_
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# clear file &quot;file_&quot; and put &quot;hello&quot; into it.&lt;/span&gt;&lt;/i&gt;
$ ls -l file_
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# check it size - &quot;hello&quot; is 5 bytes + &quot;new line&quot; symbol&lt;/span&gt;&lt;/i&gt;
-rw-r--r-- 1 user user &lt;b&gt;6&lt;/b&gt; Jul  7 10:38 file_
$ echo q &amp;gt; file_
$ ls -l file_ 
-rw-r--r-- 1 user user &lt;b&gt;2&lt;/b&gt; Jul  7 10:38 file_&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;b&gt;&amp;gt;&amp;gt;&lt;/b&gt;&lt;br /&gt;
appends only to the end of file (creates the file if not present).&lt;pre&gt;$ echo Hello &amp;gt;&amp;gt; myfile
$ ls -l myfile
-rw-r--r-- 1 user user &lt;b&gt;6&lt;/b&gt; Jul  7 10:38 myfile
$ echo world &amp;gt;&amp;gt; myfile
$ ls -l myfile
-rw-r--r-- 1 user user &lt;b&gt;12&lt;/b&gt; Jul  7 10:38 myfile&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;Note 1:&lt;/b&gt;&lt;/i&gt; by default it redirects to file from &lt;i&gt;stdout&lt;/i&gt; which refers as stream &lt;b&gt;1&lt;/b&gt;, in the meantime &lt;i&gt;stderr&lt;/i&gt; refers as stream &lt;b&gt;2&lt;/b&gt;.&lt;br /&gt;
&lt;pre&gt;$ ls -l myfile 1&gt; list.txt
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# redirects &lt;b&gt;stdout&lt;/b&gt; into list.txt file&lt;/span&gt;&lt;/i&gt;
$ cat list.txt
-rw-r--r-- 1 user user 12 Jul  7 10:38 myfile
$ ls -l smthfile &lt;b&gt;1&lt;/b&gt;&amp;gt; list.err
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# there is no file &lt;b&gt;smthfile&lt;/b&gt; - error should happen&lt;/span&gt;&lt;/i&gt;
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# redirects &lt;b&gt;stdout&lt;/b&gt; into list.err file, stderr will be printed&lt;/span&gt;&lt;/i&gt;
&lt;b&gt;ls: cannot access smthfile: No such file or directory&lt;/b&gt;
$ cat list.err 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# list.err is empty&lt;/span&gt;&lt;/i&gt;
$ ls -l smthfile &lt;b&gt;2&lt;/b&gt;&amp;gt; list.err
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# redirects &lt;b&gt;stdout&lt;/b&gt; into list.err file&lt;/span&gt;&lt;/i&gt;
$ cat list.err 
ls: cannot access smthfile: No such file or directory
&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;Note 2:&lt;/b&gt;&lt;/i&gt; It&#39;s possible to redirect one stream into another:&lt;br /&gt;
&lt;pre&gt;$ ls -l smthfile &lt;b&gt;1&lt;/b&gt;&amp;gt; list.err &lt;b&gt;2&lt;/b&gt;&amp;gt;&lt;b&gt;&amp;amp;1&lt;/b&gt;
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# redirects stdout into list.err file, after stderr redirects into stdout&lt;/span&gt;&lt;/i&gt;
$ cat list.err 
ls: cannot access smthfile: No such file or directory
&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;Note 3:&lt;/b&gt;&lt;/i&gt; There is a special file &lt;b&gt;&lt;i&gt;/dev/null&lt;/i&gt;&lt;/b&gt; is like a black hole - discards all data written to it.&lt;br /&gt;
&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;Note 4:&lt;/b&gt; I refer to this content of &lt;b&gt;myfile&lt;/b&gt; further&lt;/i&gt;.&lt;br /&gt;
&lt;h2&gt;&lt;b&gt; command1 | command2&lt;/b&gt;&lt;/h2&gt;output of &lt;i&gt;command1&lt;/i&gt; is the input for &lt;i&gt;command2&lt;/i&gt; or &lt;b&gt;&lt;i&gt;piping data through commands&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ echo &quot;Hello&quot; | grep o
Hell&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;o&lt;/span&gt;&lt;/b&gt;
$ cat myfile | grep o
Hell&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;o&lt;/span&gt;&lt;/b&gt;
w&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;o&lt;/span&gt;&lt;/b&gt;rld
$ cat myfile | grep o | grep w
&lt;b&gt;&lt;span style=&quot;color:#800;&quot;&gt;w&lt;/span&gt;&lt;/b&gt;orld&lt;/pre&gt;It&#39;s possible to use sequence of pipes - the output of one command is the input for the following.&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Note:&lt;/i&gt;&lt;/b&gt; keep common sentence in the piping. There are several bad and good practices:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;cat&lt;/b&gt; &amp;amp; &lt;b&gt;grep&lt;/b&gt;&lt;br /&gt;
to filter lines matches the patten&lt;br /&gt;
&lt;b&gt;Bad&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ cat myfile | grep e
Hello&lt;/pre&gt;&lt;b&gt;Good&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ grep e myfile
Hello&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;cat&lt;/b&gt; &amp;amp; &lt;b&gt;grep&lt;/b&gt; &amp;amp; &lt;b&gt;wc&lt;/b&gt;&lt;br /&gt;
to calculate a number of lines which match the pattern&lt;br /&gt;
&lt;b&gt;Very Bad&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ cat myfule | grep o | wc -l
2&lt;/pre&gt;&lt;b&gt;Bad&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ grep o myfile | wc -l
2&lt;/pre&gt;&lt;b&gt;Good&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ grep -c o myfile 
2&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?tr&quot;&gt;tr&lt;/a&gt;&lt;/b&gt; [from-symbol-set] [to-symbol-set]&lt;/h2&gt;&lt;b&gt;tr&lt;/b&gt;anslate characters&lt;br /&gt;
&lt;i&gt;Example&lt;/i&gt; Shift to one letter left&lt;br /&gt;
&lt;pre&gt;$ echo 12ABC | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 BCDEFGHIJKLMNOPQRSTUVWXYZ@123456789_
23BCD&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; &lt;b&gt;tr&lt;/b&gt; knows several predefined symbol classes:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;[:alpha:] - alphabetic characters&lt;/li&gt;
&lt;li&gt;[:digit:] - numeric characters&lt;/li&gt;
&lt;li&gt;[:alnum:] - alphanumeric (alphabetic + numbers) characters&gt;&lt;/li&gt;
&lt;li&gt;[:lower:] - lower-case alphabetic characters&lt;/li&gt;
&lt;li&gt;[:upper:] - upper-case alphabetic characters&lt;/li&gt;
&lt;i&gt;and others...&lt;/i&gt;&lt;/ul&gt;&lt;pre&gt;$ echo xABCDEF12 | tr &quot;[:upper:]&quot; &quot;[:lower:]&quot;
xabcdef12&lt;/pre&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://www.gnu.org/software/sed/manual/sed.html&quot;&gt;sed&lt;/a&gt; &lt;i&gt;[options] &lt;/i&gt; &lt;i&gt;file&lt;/i&gt;&lt;/b&gt;&lt;/h2&gt;The &lt;b&gt;s&lt;/b&gt;tream &lt;b&gt;ed&lt;/b&gt;itor&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;s&lt;/b&gt; for replacement by pattern&lt;br /&gt;
The rule is &lt;br /&gt;
&lt;i&gt;s &lt;b&gt; separator &lt;/b&gt; pattern &lt;b&gt; separator &lt;/b&gt; replacement &lt;b&gt; separator &lt;/b&gt; options &lt;/i&gt;&lt;br /&gt;
&lt;pre&gt;$ echo &quot;Hello world&quot; | sed &quot;s/o/z/&quot;
Hellz world
&lt;/pre&gt;&lt;b&gt;Note&lt;/b&gt;: pattern is regular expression. Be careful, read more about &lt;a href=&quot;http://www.gnu.org/software/sed/manual/sed.html#Regular-Expressions&quot;&gt;sed&#39;s regexp dialect&lt;/a&gt;.&lt;br /&gt;
&lt;pre&gt;$ echo &quot;Hello world&quot; | sed &quot;s/./z/g&quot;
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# . (dot) is special symbol in terms of regular expression
# means any character&lt;/span&gt;&lt;/i&gt;
zzzzzzzzzzz
&lt;/pre&gt;&lt;b&gt;Hint #1&lt;/b&gt;: use option &lt;b&gt;g&lt;/b&gt; to replace globally&lt;br /&gt;
&lt;pre&gt;$ echo &quot;Hello world&quot; | sed &quot;s/o/z/g&quot;
Hellz wzrld
&lt;/pre&gt;&lt;b&gt;Hint #2&lt;/b&gt;: use option &lt;b&gt;i&lt;/b&gt; to ignore case&lt;br /&gt;
&lt;pre&gt;$ echo &quot;HellO world&quot; | sed &quot;s/o/z/gi&quot;
Hellz wzrld
&lt;/pre&gt;&lt;b&gt;Hint #3&lt;/b&gt;: it doesn&#39;t necessary to use separator symbol &lt;b&gt;/&lt;/b&gt; (slash) - use any suitable for you to match the rule&lt;br /&gt;
&lt;pre&gt;$ echo &quot;HellO world&quot; | sed &quot;s,o,z,gi&quot;
Hellz wzrld
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;chain of seds&lt;br /&gt;
Instead of sed chain (through piping) it&#39;s much better to use &lt;b&gt;;&lt;/b&gt; (semicolon)&lt;br /&gt;
&lt;pre&gt;&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# it&#39;s &lt;b&gt;not good&lt;/b&gt;:&lt;/span&gt;&lt;/i&gt;
$ echo &quot;Hello world&quot; | sed &quot;s,o,z,g&quot; | sed &quot;s,z,o,g&quot;
Hello world
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# &lt;b&gt;the best&lt;/b&gt; way:&lt;/span&gt;&lt;/i&gt;
$ echo &quot;Hello world&quot; | sed &quot;s,o,z,g ; s,z,o,g&quot;
Hello world&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;y&lt;/b&gt; by-char replacement, similar to &lt;b&gt;tr&lt;/b&gt;&lt;pre&gt;$ echo 12ABC | sed &quot;y,ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,BCDEFGHIJKLMNOPQRSTUVWXYZ@123456789_,&quot;
23BCD&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;multilines&#39;n&#39;file operations&lt;br /&gt;
Suppose we have file &lt;i&gt;somefile&lt;/i&gt; with these lines:&lt;pre&gt;foo
1234
1234-foo-bar
bar
foo-bar&lt;/pre&gt;&lt;pre&gt;$ sed &quot;/foo/d&quot; somefile 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# delete all lines that matches the pattern&lt;/span&gt;&lt;/i&gt;
1234
bar
$ sed &quot;s,foo,bar,&quot; somefile 
bar
1234
1234-bar-bar
bar
bar-bar
$ sed &#39;3s,foo,bar,&#39; somefile 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# change only 3rd line of somefile&lt;/span&gt;&lt;/i&gt;
foo
1234
1234-bar-bar
bar
foo-bar
$ sed &#39;1,3s,foo,bar,&#39; somefile 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# change from 1st up to 3rd lines of somefile&lt;/span&gt;&lt;/i&gt;
bar
1234
1234-bar-bar
bar
foo-bar
$ sed &#39;3!s,foo,bar,&#39; somefile 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# change all but 3rd line of somefile&lt;/span&gt;&lt;/i&gt;
bar
1234
1234-foo-bar
bar
bar-bar
&lt;/pre&gt;and the some dangerous, but useful - in file replacement&lt;br /&gt;
&lt;pre&gt;$ sed -i.orig &#39;3!s,foo,bar,&#39; somefile 
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# creates backup file somefile.orig
# replace foo at all lines but the 3rd&lt;/span&gt;&lt;/i&gt;
$ cat somefile
bar
1234
1234-foo-bar
bar
bar-bar
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?diff&quot;&gt;diff&lt;/a&gt;&lt;/b&gt; &lt;i&gt;[options]&lt;/i&gt; &lt;i&gt;from-file&lt;/i&gt; &lt;i&gt;to-file&lt;/i&gt;&lt;/h2&gt;&lt;i&gt;diff&lt;/i&gt;erence between two files&lt;br /&gt;
&lt;pre&gt;$ diff -u somefile.orig somefile
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;#  the unified output format:
# - (minus) means what&#39;re lines have been removed
# + (plus) means what&#39;re lines have been added&lt;/span&gt;&lt;/i&gt;
--- somefile.orig 2012-08-19 12:56:58.000000000 +0400
+++ somefile 2012-08-19 13:19:21.000000000 +0400
@@ -1,5 +1,5 @@
-foo
+bar
 1234
 1234-foo-bar
 bar
-foo-bar
+bar-bar&lt;/pre&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?awk&quot;&gt;awk&lt;/a&gt; &lt;i&gt;script&lt;/i&gt;&lt;/b&gt;&lt;/h2&gt;awk is rich scripting language itself that&#39;s present on nearly ever unix-like machine. &lt;br /&gt;
That&#39;s why look at the most frequently used cases:&lt;br /&gt;
&lt;pre&gt;$ echo &quot;This is world&quot; | awk &#39;{print $3;}&#39;
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# prints 3rd column
# $N refers to Nth column (of stream or from file)&lt;/span&gt;&lt;/i&gt;
world
$ echo &quot;This,is,world&quot; | awk &#39;{split($1,X,&quot;,&quot;);print X[3]&quot; &quot;X[2];}&#39;
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# splits 1st column using , (comma) as separator
# result is X array
# prints 3rd and 2nd items of X array&lt;/span&gt;&lt;/i&gt;
world is
$ awk &#39;{c++}END{print c;}&#39; somefile
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# increase counter &lt;b&gt;c&lt;/b&gt; on each line by one
# at the end prints out its value = number of lines in file&lt;/span&gt;&lt;/i&gt;
5&lt;/pre&gt;&lt;h2&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?bc&quot;&gt;bc&lt;/a&gt;&lt;/b&gt;&lt;/h2&gt;An ar&lt;b&gt;b&lt;/b&gt;itrary precision &lt;b&gt;c&lt;/b&gt;alculator language. &lt;br /&gt;
&lt;br /&gt;
The powerful tool with amazing set of math functionality: power calculation, exponent, sine, cosine, arctangent, natural logarithm, squared root, transform from one numeral system into another (e.g from decimal into binary, hexadecimal and vice-verse).&lt;br /&gt;
&lt;br /&gt;
It&#39;s too rich, that&#39;s why i&#39;d like to describe it briefly:&lt;br /&gt;
&lt;pre&gt;$ echo &quot;2*3/7&quot; | bc -l
.85714285714285714285
$ echo &quot;10^6/4&quot; | bc -l
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# quarter of one million&lt;/span&gt;&lt;/i&gt;
250000.00000000000000000000
$ echo &quot;l(10)&quot; | bc -l
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# natural logarithm of 10&lt;/span&gt;&lt;/i&gt;
2.30258509299404568401
&lt;i&gt;&lt;span style=&quot;color:#080&quot;&gt;# keep in mind relation  &lt;img src=&quot;http://latex.codecogs.com/gif.latex?\inline%20\dpi{120}%20\log_n{k}=\ln{k}/\ln{n}&quot;/&gt;
# calculate &lt;img src=&quot;http://latex.codecogs.com/gif.latex?%5Clog_2%7B10%7D&quot;/&gt;&lt;/span&gt;&lt;/i&gt;
$ echo &quot;l(10)/l(2)&quot; | bc -l
3.32192809488736234789

&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# converting to/from different numerical systems&lt;/span&gt;&lt;/i&gt;

$ echo &quot;obase=16;254&quot; | bc -l
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# convert 254 to hexadecimal (output base is 16)&lt;/span&gt;&lt;/i&gt;
FE
$ echo &quot;ibase=2;101&quot; | bc -l
&lt;i&gt;&lt;span style=&quot;color:#080;&quot;&gt;# convert from binary (input base is 2) to decimal (default)&lt;/span&gt;&lt;/i&gt;
5
&lt;/pre&gt;</description><link>http://dolzhenko.blogspot.com/2012/08/bash-let-me-bash-that-for-you-part-1.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-5958563547629871354</guid><pubDate>Tue, 14 Aug 2012 18:40:00 +0000</pubDate><atom:updated>2012-08-19T21:52:00.957+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">bash</category><category domain="http://www.blogger.com/atom/ns#">hints</category><title>Bash: Let me bash that for you, Part 0</title><description>I was going to write about some &lt;i&gt;Unix-like&lt;/i&gt; shell hints which I usually use like &lt;i&gt;grep&lt;/i&gt;, &lt;i&gt;sed&lt;/i&gt;, &lt;i&gt;for&lt;/i&gt; loop, variables and so on. I noticed that I do usually use lots of &lt;i&gt;bash&lt;/i&gt; kung-fu beyond the shadow of a doubt. &lt;br /&gt;
&lt;br /&gt;
I&#39;m not going to start a holly war what shell is the best one - &lt;i&gt;sh&lt;/i&gt;, &lt;i&gt;ksh&lt;/i&gt; or whatever. I know how to cook &lt;i&gt;bash&lt;/i&gt; tasty - it has lots in common with &lt;i&gt;sh&lt;/i&gt; but some nuances happen. &lt;br /&gt;
&lt;br /&gt;
That isn&#39;t a bash tutorial or so - it&#39;s more like commonly used hints and tips.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?man&quot;&gt;man&lt;/a&gt; anycommand&lt;/h2&gt;Each man has to know &lt;i&gt;unix&lt;/i&gt; command &lt;b&gt;man&lt;/b&gt;. That&#39;s &lt;b&gt;man&lt;/b&gt;ual, dude.&lt;br /&gt;
&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?pwd&quot;&gt;&lt;b&gt;pwd&lt;/b&gt;&lt;/a&gt;&lt;/h2&gt;prints &lt;b&gt;p&lt;/b&gt;ath of &lt;b&gt;w&lt;/b&gt;orking &lt;b&gt;d&lt;/b&gt;irectory&lt;pre&gt;$ pwd 
/home/user&lt;/pre&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?ls&quot;&gt;ls&lt;/a&gt; &lt;i&gt;path&lt;/i&gt;&lt;/h2&gt;&lt;b&gt;l&lt;/b&gt;i&lt;b&gt;s&lt;/b&gt;t of directory&lt;pre&gt;$ ls /tmp
myfile
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; &lt;b&gt;.&lt;/b&gt; (dot) in unix-like systems is current directory&lt;br /&gt;
&lt;pre&gt;$ ls .
myfile
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; when path isn&#39;t specified &lt;i&gt;ls&lt;/i&gt; uses current directory&lt;br /&gt;
&lt;pre&gt;$ ls 
myfile
&lt;/pre&gt;&lt;i&gt;Hint:&lt;/i&gt; option &lt;i&gt;-l&lt;/i&gt; prints a long file format with ownership info, file size and so on&lt;br /&gt;
&lt;pre&gt;$ ls -l 
-rw-r--r-- 1 user user 12 Jul  7 11:00 myfile
&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Hint:&lt;/i&gt; option &lt;i&gt;-h&lt;/i&gt; prints file size in human readable format - Kilobytes, Megabytes etc &lt;pre&gt;$ ls -lh Java\ Concurrency\ In\ Practice.pdf 
-rw-r--r-- 1 user user 3.9M May 22  2009 Java Concurrency In Practice.pdf&lt;/pre&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?cd&quot;&gt;cd&lt;/a&gt; &lt;i&gt;path&lt;/i&gt;&lt;/h2&gt;&lt;b&gt;c&lt;/b&gt;hange &lt;b&gt;d&lt;/b&gt;irectory&lt;pre&gt;$ cd /tmp &lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;cd path/of/my/destination/&lt;/b&gt;&lt;br /&gt;
&lt;i&gt;Hint:&lt;/i&gt; I prefer use &lt;i&gt;cd target/destitaton/path&lt;/i&gt; instead of several &lt;i&gt;cd&lt;/i&gt;. It&#39;s much better, believe me. That&#39;s the benefit :&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;cd -&lt;/b&gt;&lt;br /&gt;
return back to previous directory in the change directory history&lt;br /&gt;
&lt;pre&gt;$ pwd 
/tmp
$ mkdir -p a/b/c/d/e
$ cd a/b/c/d
$ pwd
/tmp/a/b/c/d
$ cd -
$ pwd
/tmp&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;revert search over bash command history&lt;br /&gt;
It&#39;s possible to search in already executed commands using &lt;i&gt;bash&lt;/i&gt;.&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;r&lt;/i&gt;&lt;/b&gt; &lt;i&gt;typing&lt;/i&gt;&lt;br /&gt;
For instance&lt;br /&gt;
&lt;pre&gt;// Ctrl + r cd a
$ cd a/b/c/d
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;cd ~&lt;/b&gt;&lt;br /&gt;
move to home directory&lt;br /&gt;
&lt;pre&gt;$ cd ~
$ pwd
/home/user&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;cd&lt;/b&gt;&lt;br /&gt;
shortcut for &lt;b&gt;cd ~&lt;/b&gt;&lt;br /&gt;
&lt;pre&gt;$ cd
$ pwd
/home/user&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ul&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?chown&quot;&gt;chown&lt;/a&gt; &lt;i&gt;options&lt;/i&gt; &lt;i&gt;owner&lt;/i&gt;:&lt;i&gt;group&lt;/i&gt; filename(s)&lt;/h2&gt;&lt;b&gt;ch&lt;/b&gt;anges &lt;b&gt;own&lt;/b&gt;ership of file(s). Every file in &lt;i&gt;Unix&lt;/i&gt; has user ownership, group and other permissions. &lt;pre&gt;$ ls -la myfile
-rw-r----- 1 user user 12 Jul  7 11:00 myfile
$ chown user2 myfile
$ ls -la myfile
-rw-r----- 1 user2 user 12 Jul  7 11:00 myfile
&lt;/pre&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?chmod&quot;&gt;chmod&lt;/a&gt; &lt;i&gt;options&lt;/i&gt; filename(s)&lt;/h2&gt;&lt;b&gt;ch&lt;/b&gt;anges &lt;b&gt;mod&lt;/b&gt;e file(s). Every file (in general directory is file too) in &lt;i&gt;Unix&lt;/i&gt; has three permissions: &lt;ul&gt;&lt;li&gt;&lt;b&gt;u&lt;/b&gt;ser (owner)&lt;/li&gt;
&lt;li&gt; &lt;b&gt;g&lt;/b&gt;roup&lt;/li&gt;
&lt;li&gt;&lt;b&gt;o&lt;/b&gt;thers&lt;/li&gt;
&lt;/ul&gt;There are three types of permissions:&lt;ul&gt;&lt;li&gt;&lt;b&gt;r&lt;/b&gt;ead = 4&lt;/li&gt;
&lt;li&gt; &lt;b&gt;w&lt;/b&gt;rite = 2&lt;/li&gt;
&lt;li&gt;e&lt;b&gt;x&lt;/b&gt;ecute = 1&lt;/li&gt;
&lt;/ul&gt;Two ways how to change mode: &lt;ul&gt;&lt;li&gt;numeric:&lt;br /&gt;
1st digit corresponds to &lt;b&gt;u&lt;/b&gt;ser permissions.&lt;br /&gt;
2nd digit corresponds to &lt;b&gt;g&lt;/b&gt;roup permissions.&lt;br /&gt;
3rd digit corresponds to &lt;b&gt;o&lt;/b&gt;ther permissions.&lt;br /&gt;
&lt;br /&gt;
Every digit is sum of permission type, e.g.&lt;br /&gt;
&lt;b&gt;r&lt;/b&gt;ead + &lt;b&gt;w&lt;/b&gt;rite = 4 + 2 = 6&lt;br /&gt;
&lt;b&gt;r&lt;/b&gt;ead + &lt;b&gt;w&lt;/b&gt;rite + e&lt;b&gt;x&lt;/b&gt;ecute = 4 + 2 + 1 = 7&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Note:&lt;/i&gt; When change mode it doesn&#39;t keep previous permissions - permission type = 6 means that it has read + write but &lt;b&gt;no&lt;/b&gt; executable.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;pre&gt;$ chmod 640 myfile
$ ls -la myfile
-rw-r----- 1 user user 12 Jul  7 11:00 myfile
$ chmod 754 myfile
$ ls -la myfile
-rwxr-xr-- 1 user user 12 Jul  7 11:00 myfile
&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;symbolic&lt;br /&gt;
Change permission in human readable way:&lt;br /&gt;
u+r grants &lt;b&gt;r&lt;/b&gt;eadable permission to &lt;b&gt;u&lt;/b&gt;ser&lt;br /&gt;
g-w removes &lt;b&gt;w&lt;/b&gt;ritable permission from &lt;b&gt;g&lt;/b&gt;roup&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Note:&lt;/i&gt; In this case &lt;b&gt;chmod&lt;/b&gt; keeps previous permissions.&lt;/li&gt;
&lt;pre&gt;$ ls -la myfile
-rwxr-xr-- 1 user user 12 Jul  7 11:00 myfile
$ chmod o-r myfile
$ ls -la myfile
-rwxr-x--- 1 user user 12 Jul  7 11:00 myfile
$ chmod g+w myfile
$ ls -la myfile
-rwxrwx--- 1 user user 12 Jul  7 11:00 myfile
&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Background and foreground processes&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Hotkey &lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;z&lt;/i&gt;&lt;/b&gt; stops/resumes command execution&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ gzip application.log 
^Z
[1]+  Stopped                gzip application.log
&lt;/pre&gt;It means that we&#39;ve got job #1 which is &lt;i&gt;gzip application.log&lt;/i&gt; has state &lt;i&gt;Stopped&lt;/i&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?jobs&quot;&gt;jobs&lt;/a&gt; &lt;/b&gt;&lt;br /&gt;
get the current bash session job list&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ jobs
[1]+  Stopped                gzip application.log&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?fg&quot;&gt;fg&lt;/a&gt; &lt;i&gt;job#&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
move job &lt;i&gt;job#&lt;/i&gt; to foreground&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ fg 1
gzip application.log&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?bg&quot;&gt;bg&lt;/a&gt; &lt;i&gt;job#&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
move job &lt;i&gt;job#&lt;/i&gt; to background&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ bg 1
[1]+ gzip application.log &amp;amp;
$
[1]+  Done                    gzip application.log&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;command &lt;i&gt;&amp;amp;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
move &lt;i&gt;command&lt;/i&gt; execution to background&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ gzip application.log &amp;amp;
[1] 364
$ jobs
[1]+ Running                 gzip application.log
$
[1]+  Done                   gzip application.log&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?wait&quot;&gt;wait&lt;/a&gt; &lt;i&gt;pid&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
wait while background processes with &lt;i&gt;pid&lt;/i&gt; will be finished&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;$ gzip application.log &amp;amp;
[1] 415
$ wait 415
[1]+  Done                   gzip application.log&lt;/pre&gt;&lt;/li&gt;
&lt;i&gt;Hint:&lt;/i&gt; use simple &lt;b&gt;wait&lt;/b&gt; to await to finish all background processes. &lt;/ul&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?history&quot;&gt;history&lt;/a&gt; &lt;i&gt;number-of-items&lt;/i&gt;&lt;/h2&gt;prints last &lt;i&gt;number-of-items&lt;/i&gt; (if specified or all otherwise) executed commands. &lt;pre&gt;$ history 3
  558  ls
  559  cd ~/
  560  history 
&lt;/pre&gt;&lt;b&gt;Hint:&lt;/b&gt; to run &lt;i&gt;n&lt;/i&gt;-th command in history use &lt;i&gt;exclamation mark&lt;/i&gt; &lt;pre&gt;$ !558
ls
file                              myfile
&lt;/pre&gt;&lt;b&gt;Hint:&lt;/b&gt; to run last command use &lt;i&gt;double&lt;/i&gt; exclamation mark &lt;pre&gt;$ !!
ls
file                              myfile
&lt;/pre&gt;&lt;h2&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?sleep&quot;&gt;sleep&lt;/a&gt; &lt;i&gt;seconds&lt;/i&gt;&lt;/h2&gt;sleep for a specified number of seconds &lt;pre&gt;$ date ; sleep 5; date
Sat Jul  7 22:47:36 MSK 2012
Sat Jul  7 22:47:41 MSK 2012&lt;/pre&gt;&lt;h2&gt;Hot keys&lt;/h2&gt;&lt;pre&gt;&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;a&lt;/i&gt;&lt;/b&gt; - move cursor to the beginning of the line
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;e&lt;/i&gt;&lt;/b&gt; - move cursor to the end of the line

&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;u&lt;/i&gt;&lt;/b&gt; - delete from cursor position to the beginning of the line 
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;k&lt;/i&gt;&lt;/b&gt; - delete from cursor position to the end of the line 
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;w&lt;/i&gt;&lt;/b&gt; - delete from cursor position to the beginning of the word 


&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;r&lt;/i&gt;&lt;/b&gt; - search in the history of executed commands

&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;l&lt;/i&gt;&lt;/b&gt; - clear screen
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;d&lt;/i&gt;&lt;/b&gt; - shortcut for &lt;i&gt;exit&lt;/i&gt;

&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;z&lt;/i&gt;&lt;/b&gt; - stop/resume command background execution
&lt;b&gt;&lt;i&gt;Ctrl&lt;/i&gt;&lt;/b&gt; + &lt;b&gt;&lt;i&gt;c&lt;/i&gt;&lt;/b&gt; - cancel foreground command execution

&lt;b&gt;&lt;i&gt;Esc&lt;/i&gt;&lt;/b&gt; &lt;b&gt;&lt;i&gt;.&lt;/i&gt;&lt;/b&gt; (dot) - add last argument of last executed command
&lt;/pre&gt;Now, let&#39;s go and conquer the world.</description><link>http://dolzhenko.blogspot.com/2012/08/bash-let-me-bash-that-for-you-part-0.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-5250553302784912309</guid><pubDate>Sat, 16 Jun 2012 20:15:00 +0000</pubDate><atom:updated>2012-06-17T09:50:14.523+04:00</atom:updated><title>Принцип Дирихле</title><description>Кажется, это было ещё в седьмом классе, когда упоминался принцип Дирихле:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;quote&quot;&gt;Если есть &lt;span class=&quot;b i&quot;&gt;M&lt;/span&gt; предметов, которые надо разложить по &lt;span class=&quot;b i&quot;&gt;N&lt;/span&gt; ящиков, причём &lt;span class=&quot;b i&quot;&gt;M&lt;/span&gt; &amp;gt; &lt;span class=&quot;b i&quot;&gt;N&lt;/span&gt;, тогда хотя бы в одном ящике будет более &lt;span class=&quot;b i&quot;&gt;одного&lt;/span&gt; предмета.&lt;/div&gt;&lt;br /&gt;
К этому прилагалась задача типа: население Москвы 10 млн человек, среднее кол-во волос у человека 1.5млн, у скольких людей в мск одинаковое кол-во волос. &lt;br /&gt;
&lt;br /&gt;
Сейчас я работаю в очень высоком здании, в котором много этажей и компаний - например, едет в лифте 6 человек и лифт будет останавливаться на 3 этажах. Казалось бы всё очевидно - где-то выйдет более, чем один человек. &lt;br /&gt;
&lt;br /&gt;
Можно ли сказать что-то больше ? Например, что на каждом этаже выйдет по 2 человека ?&lt;br /&gt;
&lt;br /&gt;
Используя &lt;span class=&quot;i&quot;&gt;метод пристального взгляда&lt;/span&gt; часто можно определить, что незнакомые люди работают в одной компании - как правило это либо, соблюдение ими дресс кода, либо просто то, что они друг с другом общаются.&lt;br /&gt;
&lt;br /&gt;
т.о. зная что-то о специфике данных можно дать более точный и лучший ответ. &lt;br /&gt;
&lt;br /&gt;
Один из наглядных примеров - упаковка доменных объектов в пачки (&lt;span class=&quot;i&quot;&gt;batches&lt;/span&gt;). &lt;br /&gt;
&lt;br /&gt;
Так записывая каждый объект в поток напрямую мы получаем объём данных &lt;br /&gt;
&lt;span class=&quot;b&quot;&gt;V&lt;/span&gt; ~ O(&lt;span class=&quot;b i&quot;&gt;N&lt;/span&gt;), &lt;br /&gt;
в то время как зная о специфике данных, о том, что это пачка, можно достигать &lt;br /&gt;
&lt;span class=&quot;b&quot;&gt;V&lt;/span&gt; &amp;gt;&amp;gt; O(&lt;span class=&quot;b i&quot;&gt;N&lt;/span&gt;).</description><link>http://dolzhenko.blogspot.com/2012/06/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8870493191508591473.post-6358955404225482217</guid><pubDate>Sun, 06 May 2012 16:28:00 +0000</pubDate><atom:updated>2012-05-16T08:20:58.616+04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">задачка</category><title>задачка: синие и красные в мешках</title><description>&lt;div class=&quot;quote&quot;&gt;Есть &lt;span class=&quot;b&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;b&quot; style=&quot;color:blue;&quot;&gt;синих&lt;/span&gt; бумажек и &lt;span class=&quot;b&quot;&gt;50&lt;/span&gt; таких же, но &lt;span class=&quot;b&quot; style=&quot;color:red;&quot;&gt;красных&lt;/span&gt;. &lt;br /&gt;
&lt;br /&gt;
Как их надо разложить по двум мешкам, чтобы человек, вытащив одну бумажку один раз из любого мешка с максимальной вероятностью вытащил &lt;span class=&quot;b&quot; style=&quot;color:blue;&quot;&gt;синию&lt;/span&gt; бумажку.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;b i&quot;&gt;внимание!&lt;/span&gt;  комментарии содержат ответ.</description><link>http://dolzhenko.blogspot.com/2012/05/blog-post.html</link><author>noreply@blogger.com (Vladimir Dolzhenko)</author><thr:total>3</thr:total></item></channel></rss>