Archive | Miscellaneous RSS for this section

Cross-Language Compiler Benchmarking: Are We Fast Yet?

Research on programming languages is often more fun when we can use our own languages. However, for research on performance optimizations that can be a trap. In the end, we need to argue that what we did is comparable to state-of-the-art language implementations. Ideally, we are able to show that our own little language is not just a research toy, but that it is, at least performance-wise, competitive with for instance Java or JavaScript VMs.

Over the last couple of years, it was always a challenge for me to argue that SOM or SOMns are competitive. There were those 2-3 paragraphs in every paper that never felt quite as strong as they should be. And the main reason was that we don’t really have good benchmarks to compare across languages.

I hope we finally have reasonable benchmarks for exactly that purpose with our Are We Fast Yet? project. To track performance of benchmarks, we also set up a Codespeed site, which shows the various results. The preprint has already been online for a bit, but next week, we are finally going to present the work at the Dynamic Languages Symposium in Amsterdam.

Please find abstract and details below:

Abstract

Comparing the performance of programming languages is difficult because they differ in many aspects including preferred programming abstractions, available frameworks, and their runtime systems. Nonetheless, the question about relative performance comes up repeatedly in the research community, industry, and wider audience of enthusiasts.

This paper presents 14 benchmarks and a novel methodology to assess the compiler effectiveness across language implementations. Using a set of common language abstractions, the benchmarks are implemented in Java, JavaScript, Ruby, Crystal, Newspeak, and Smalltalk. We show that the benchmarks exhibit a wide range of characteristics using language-agnostic metrics. Using four different languages on top of the same compiler, we show that the benchmarks perform similarly and therefore allow for a comparison of compiler effectiveness across languages. Based on anecdotes, we argue that these benchmarks help language implementers to identify performance bugs and optimization potential by comparing to other language implementations.

  • Cross-Language Compiler Benchmarking: Are We Fast Yet? Stefan Marr, Benoit Daloze, Hanspeter Mössenböck; In Proceedings of the 12th Symposium on Dynamic Languages (DLS ’16), ACM, 2016.
  • Paper: HTML, PDF, DOI
  • BibTex: BibSonomy

Replacing plyr’s ddply with data.table to improve an R script’s performance

Since quite a while, I am using R as a scripting language to generate graphs to the benchmarking results of various experiments. Since we have a new 64 core machine at the lab, I happen to run into performance issues with scripts that process the benchmark results, because the number of measurements increased significantly and the plyr library I use was designed with ease of use in mind, instead of performance. Concretely, I was experiencing script runtimes of up to 25min for a data set with roughly 50.000 measurements.

Fortunately, it is a know issue and a quick search turned up various options to improve performance. Since my initial choice for plyr was based on its intuitive DSL, I was looking for something that is similarly nice, but a lot faster. This blog post is meant to briefly document my findings for myself, and remind me how to use the data.table package, I chose.

Plyr’s ddply can be extremely slow

In an earlier post, I already outlined briefly how I use R to process benchmarking results. So far, I used ddply mostly with the transform and summarize functions to normalize measurements and to calculate averages, standard deviation, or speedup factors.

The problematic examples are for instance the following normalization and aggregation operations:

process_data <- function(data, baseline) {
  norm <- ddply(data, ~ Benchmark + Cores,
                function(x) transform(x,
                                      RuntimeRatio = Time / mean(Time[VirtualMachine == baseline]),
                                      SpeedupRatio = mean(Time[VirtualMachine == baseline]) / Time))

  # Calculate basic aggregates
  stats <- ddply(norm, ~ Cores + Benchmark + VirtualMachine,
                 summarise,
                 Time.mean                 = mean(Time),
                 Time.stddev               =   sd(Time),

                 RuntimeRatio.mean         = mean(RuntimeRatio),
                 RuntimeRatio.geomean      = geometric.mean(RuntimeRatio),
                 SpeedupRatio.mean         = mean(SpeedupRatio),
                 SpeedupRatio.geomean      = geometric.mean(SpeedupRatio),

                 NumberOfMeasurements      = length(Time),

                 RuntimeRatio.stddev       = sd(RuntimeRatio),
                 RuntimeRatio.scaled_sd    = RuntimeRatio.stddev/RuntimeRatio.geomean,
                 RuntimeRatio.variance     = var(RuntimeRatio),
                 RuntimeRatio.median       = median(RuntimeRatio),
                 # RuntimeRatio.mean095Error = confInterval095Error(RuntimeRatio),
                 # RuntimeRatio.cnfIntHigh   = RuntimeRatio.mean + RuntimeRatio.mean095Error,
                 # RuntimeRatio.cnfIntLow    = RuntimeRatio.mean - RuntimeRatio.mean095Error,

                 SpeedupRatio.stddev       = sd(SpeedupRatio),
                 SpeedupRatio.scaled_sd    = SpeedupRatio.stddev / SpeedupRatio.geomean,
                 SpeedupRatio.variance     = var(SpeedupRatio),
                 SpeedupRatio.median       = median(SpeedupRatio),
                 # SpeedupRatio.mean095Error = confInterval095Error(SpeedupRatio),
                 # SpeedupRatio.cnfIntHigh   = SpeedupRatio.mean + SpeedupRatio.mean095Error,
                 # SpeedupRatio.cnfIntLow    = SpeedupRatio.mean - SpeedupRatio.mean095Error,

                 Time.median               = median(Time)
                 # Time.mean095Error         = confInterval095Error(Time),
                 # Time.cnfIntHigh           = Time.mean + Time.mean095Error,
                 # Time.cnfIntLow            = Time.mean - Time.mean095Error
  )

  list(norm = norm, stats = stats)
}

On the object-table data set form earlier experiments, the process_data(...) function takes roughly 2.1sec to execute. Thus, is as not particular fast, but still useable. However, on the recent data sets I was using, the runtime got a severe bottleneck.

Thus, I was looking into data.table to find an alternative. The result is a rewrite of the function to the process_data_dt(...) function below. The result is a roughly 20x speedup. On the sample data mentioned, the runtime goes from 2.1sec down to 0.2sec. In my particular case, the runtime went from 25min to 1.3min. That’s still slow, but much more usable.

process_data_dt <- function(data, baseline) {
  norm <- data.table(data)
  norm[, RuntimeRatio := Time / mean(Time[VirtualMachine == baseline]), by=list(Benchmark, Cores)]
  norm[, SpeedupRatio := mean(Time[VirtualMachine == baseline]) / Time, by=list(Benchmark, Cores)]

  # Calculate basic aggregates
  stats   <- norm[, list(Time.mean                 = mean(Time),
                         Time.stddev               =   sd(Time),
                         
                         RuntimeRatio.mean         = mean(RuntimeRatio),
                         RuntimeRatio.geomean      = geometric.mean(RuntimeRatio),
                         SpeedupRatio.mean         = mean(SpeedupRatio),
                         SpeedupRatio.geomean      = geometric.mean(SpeedupRatio),
                         
                         NumberOfMeasurements      = length(Time),
                         
                         RuntimeRatio.stddev       = sd(RuntimeRatio),
                         RuntimeRatio.variance     = var(RuntimeRatio),
                         # RuntimeRatio.mean095Error = confInterval095Error(RuntimeRatio),
                         
                         
                         RuntimeRatio.median       = median(RuntimeRatio),
                         
                         SpeedupRatio.stddev       = sd(SpeedupRatio),
                         SpeedupRatio.variance     = var(SpeedupRatio),
                         SpeedupRatio.median       = median(SpeedupRatio),
                         # SpeedupRatio.mean095Error = confInterval095Error(SpeedupRatio),
                         
                         Time.median               = median(Time)
                         # Time.mean095Error         = confInterval095Error(Time)
                      ),
                  by = list(Cores, Benchmark, VirtualMachine)]
  
  # stats[, RuntimeRatio.cnfIntHigh := RuntimeRatio.mean + RuntimeRatio.mean095Error]
  # stats[, RuntimeRatio.cnfIntLow  := RuntimeRatio.mean - RuntimeRatio.mean095Error]
  stats[, RuntimeRatio.scaled_sd  := RuntimeRatio.stddev / RuntimeRatio.geomean]
  stats[, SpeedupRatio.scaled_sd  := SpeedupRatio.stddev / SpeedupRatio.geomean]
  # stats[, SpeedupRatio.cnfIntHigh := SpeedupRatio.mean + SpeedupRatio.mean095Error]
  # stats[, SpeedupRatio.cnfIntLow  := SpeedupRatio.mean - SpeedupRatio.mean095Error]
  # stats[, Time.cnfIntHigh         := Time.mean + Time.mean095Error]
  # stats[, Time.cnfIntLow          := Time.mean - Time.mean095Error]
  
  list(norm=norm, stats=stats)
}

To conclude, data.table is a nice R package that is much faster than plyr’s ddply and as you can see in the example, the provided interface is almost as nice as the one provided by ddply.

New Blog, New Design

Since I started my PhD studies at the Programming Technology Lab (PROG) at the VUB in Brussels a while ago, I had to update my pages a bit to reflect my new live as a scientist. You might have noticed, now this blog contains also some details about myself. You will find also some thoughts about my research and maybe at some point in time a real publication 🙂 My office is located here, if you like to give me a visit:
View Larger Map

Die Duet™-Idee

In der heutigen Zeit sind Computer nicht mehr aus unserem Leben wegzudenken, ein Leben ohne sie vielleicht gar unmöglich. Besonders aber Unternehmen sind abhängig von einer funktionierenden IT-Landschaft und verwenden hochkomplexe Software um z.B. ihre Buchhaltung oder Einkäufe zu erledigen oder Produktionsanlagen zu steuern. Dafür gibt es dann ERP-, SCM-, CRM- oder auch PLM-Lösungen. Eines haben sie zum überwiegenden Teil alle gemeinsam, sie sind schlecht bedienbar. Viele der auf dem Markt angebotenen Systeme sind problemorientiert und implementieren komplexe Zusammenhänge, die von ihren Nutzern oft, wenn überhaupt nur zum Teil verstanden werden. Die Oberflächen sind nicht nutzerorientiert entworfen worden sondern bilden nur die komplexen Probleme in einer oft nur schwer zu erfassenden Art und Weise ab.

Dies führt zu einer geringen Akzeptanz bei den Menschen, die diese Systeme letztendlich bedienen müssen und erfordern umfangreiche Schulungsmaßnahmen, da sie nur wenig Ähnlichkeit mit dem Nutzer bereits bekannten Systemen haben. Benutzer müssen sich erst langwierig an die Dialoge und implementierten Arbeitsabläufe gewöhnen. Dazu müssen dann auch oft die zuvor genutzten Abläufe angepasst werden. Dies führt nicht nur zum Akzeptanzproblem sonder verringert in der Lernphase auch erst einmal die Produktivität.

Eine weitere negative Tendenz zeichnet sich besonders auf höheren Ebenen der Hierarchie ab. Die für einen unternehmerischen Entscheidungsprozess benötigten Informationen werden aus Zeitmangel oder fehlender Schulung nicht selbst aus dem System bezogen um das operative Geschäft zu leiten, sondern diese Arbeit wird delegiert. Dies führt dazu, dass eigentlich vorhandene Daten für z.B. den Abteilungsleiter nicht direkt verfügbar sind.

Ziel ist es nun die Daten dort verfügbar zu machen, wo sie wirklich benötigt werden. In den meisten Fäll sollen die Daten weiterverarbeitet werden, z.B. mit einem der Office-Produkte. So benötigt man die Quartalszahlen für einen Geschäftsbericht, Kundendaten für eine Supportanfrage oder auch die Personaldaten für einen Mitarbeiter um ihm ein Zeugnis anfertigen zu können.

Integration für mehr Benutzerakzeptanz

Ideal wäre es also, wenn man die Personaldaten in Word, die Kundendaten in Outlook oder die Quartalszahlen in Excel hätte und direkt in die Dokumente übernehmen könnte. Dadurch wird zum einen ein Raussuchen der Daten über die komplexe Oberfläche des Systems vermieden und zum anderen Fehler, die beim manuellen Übertragen entstehen können, ausgeschlossen. Zudem sind die Daten in dem Programm verfügbar, das der Nutzer schon kennt. Hiermit verbessert sich die Akzeptanz beim Nutzer und der Schulungsaufwand wird gesenkt, auch weil der Nutzer bei der ihm bekannten Software experimentierfreudiger ist, da er bei Fehlern auf bekannte Funktionen wie z.B. „Rückgängig“ vertrauen kann.

Hier müssen natürlich für alle erdenklichen Anwendungsfälle und auch speziellen Unternehmensszenarien eigene Integrationen erstellt werden um den gewünschten Nutzen erreichen zu können.

Diese Idee ist nicht erst von SAP und Microsoft mit ihrem Duet™/Mendocino entwickelt worden, sondern wird von anderen Anbietern bereits seit längerer Zeit verfolgt. Für Microsoft ist diese es eigentlich erst mit dem immer relevanter werdenden OpenOffice spannend geworden sich in diese Richtung zu bewegen und ermöglicht es die Position auf dem Officemarkt zu festigen und die Bindung an eigene Lösung zu erhöhen. Zusätzlich wird durch Einsatz des MS SQL Servers als Bestandteil der Duet-Architektur die Bindung an Microsoft Infrastruktur erhöht. Für SAP ist es im Prinzip ein weitere Client, der zudem den Umstieg auf die aktuelle mySAP Version erzwingt und somit auch hier für weitere Lizenzeinnahmen sorgen kann.

Alles in allem ist die Idee also nicht neu, aber für die Anwender sicher ein Schritt in die richtige Richtung. Wenn sie dazu noch so umgesetzt wird, dass tatsächlich der Anwender im Mittelpunkt steht, könnten sich für Unternehmen die solche Lösungen einsetzen durchaus positive Effekte erzielen lassen.

Duet™, eine nette Idee?

Bachelor of Science in Software Engineering

Auf dem Weg zu meinem Bachelor of Science absolviere ich momentan die letzte Station, mein Bachelorprojekt. Eigentlich habe ich meinen Abschluss schon in der Tasche. Alle Lehrveranstaltungen sind besucht und die Noten stehen fest. Doch eines muss ich für meinen ersten berufsbefähigenden Abschluss noch tun, das Gelernte anwenden.

Dazu hat uns das HPI verschiedene Projekte zur Auswahl gestellt, wovon einige in Kooperationen mit einem Partner aus der Industrie durchgeführt werden. Ich habe mich für das Post-Projekt am Polze-Lehrstuhl entschieden. Einerseits finde ich die zu verwendenden Techniken interessant (.NET, C#, WCF usw.) und andererseits reizt mich das Thema Office-Integration. So hatte der Jahrgang vor uns bei der Post das Thema Veranstaltungsmanagement mit Hilfe von Outlook auf der Basis von Daten aus einem SAP-System.

Add-Ins für Office und SAP an sich sind Dinge, die man schon irgendwo immer mal gesehen hat und besonders SAP R/3 oder mySAP hört man ständig, aber ich hatte eine eher unwirklich Vorstellung wie das wirklich aussieht. SAP ist überall und kann alles bzw. wird für alles was irgendwie mit BWL zutun hat verwendet. Es muss riesig sein und vermutlich so etwas wie ein Dinosaurier im Vergleich zu dem mir bislang bekannten. Nicht nur in der Größe, auch in der Ausgereiftheit und Stabilität. Nun gut, Dinosaurier sind bekanntlich nicht flexibel gewesen und ausgestorben, aber dazu später vielleicht mehr.

Also SAP ist ein Buzzword das ich für mich mit reellem Inhalt füllen wollte. Dazu noch etwas Office und schon sind wir bei Duet™/Mendocino eine Idee, die sicher nicht neu ist, aber für die Zukunft zunehmend wichtiger werden dürfte. So setze sich also der erste Eindruck von dem was mich erwarten könnte zusammen und mein Favorit war gefunden.

Ein großes deutsches Unternehmen

Meinem Wunsch wurde dann auch entsprochen und ich beschäftige mich nun zusammen mit drei anderen Studenten mit diesem Thema. Ein für mich nicht unwichtiges Entscheidungskriterium bei der Projektwahl war die Tatsache, dass das Projekt direkt beim Industriepartner, einem großen deutschen Unternehmen, durchgeführt werden soll. Somit bestand die Möglichkeit aus dem bekannten universitären Umfeld auszubrechen, den Alltag in der Wirtschaft kennen zu lernen und auch mal zu sehen, wie IT-Projekte im „richtigen“ Leben durchgeführt werden. Zumindest war das meine Hoffnung.

Das „echte“ Arbeiten hab ich gesehen, ja. Allerdings ist unsere Art der Projektdurchführung, orientiert an agilen Ansätzen, doch eher mit Forschungscharakter. Es existiert kein richtiger Kunde im eigentlichen Sinne. Es gibt zwar einen kundenorientierten Bedarf, aber es wird ohne Auftrag entwickelt. Dies folgt aus der Zielsetzung des Projekts. Es soll ein Toolkit entstehen, der durch Automatisierung mit Tools und Dokumentation bzw. Tutorials die Entwicklung von Office-AddIns zur SAP-Integration vereinfachen soll. Zusätzlich soll jedoch ein konkreter Anwendungsfall implementiert werden und dies idealerweise so, dass er als Produkt einem Kunden zur Verfügung gestellt werden kann. Mit dem Anwendungsfall haben wir zwar eine gute Basis um die nötigen Bestandteile des Toolkits zu ermitteln, aber durch das Ziel ein benutzbares Produkt zu entwickeln, reichen unsere Ressourcen eigentlich nicht aus und es wird letztendlich vermutlich weder das eine noch das andere Projektziel in dem Maße erreicht, dass ich persönlich damit zufrieden bin. Aber das ist ja auch keine Projektanforderung 😉

Die nächsten Wochen werde ich die Gelegenheit nutzen ausführlicher von den gemachten Erfahrungen zu berichten. Inzwischen sind drei Monate ins Land gegangen und es beginnt die Zeit in der die Projektausarbeitung geschrieben wird. Diese Zeit möchte ich auch nutzen verschiedene Themen näher zu beleuchten, die in der Projektdokumentation keinen Platz haben. Unteranderem steht die Duet™-Idee aus Benutzungsschnittstellensicht auf meiner Liste, aber auch die Technologien, die heute verfügbar sind um eine Office-SAP-Integration realisieren zu können.