Hacking, Spiele, Physik und Politik

OpenCL: Buffer vs. mehrere Devices

Da OpenCL sowohl auf CPUs als auch auf GPUs funktioniert kommt man recht schnell in die Situation in der mehr als ein OpenCL-Device verwendet werden will. Doch was passiert in diesem Fall mit dem kostbaren, weil wenigem, Grafikkartenspeicher? Die Funktion clCreateBuffer bietet ja leider keine Möglichkeit anzugeben auf welchem Device der Speicher allokiert werden soll.

Da OpenCL sowohl auf CPUs als auch auf GPUs funktioniert kommt man recht schnell in die Situation in der mehr als ein OpenCL-Device verwendet werden will. Doch was passiert in diesem Fall mit dem kostbaren, weil wenigem, Grafikkartenspeicher? Die Funktion clCreateBuffer bietet ja leider keine Möglichkeit anzugeben auf welchem Device der Speicher allokiert werden soll. Die einfachste Variante mit mehreren OpenCL-Devices zu arbeiten ist alle in einem Context zu verwalten. In diesem Fall wird ein Buffer aber immer für alle Devices angelegt. Wird ein Speicher also nur auf einem Device benötigt muss man befürchten, dass dieser auch auf anderen Devices kostbaren Speicher verbraucht. Glücklicherweise sollte dies sowohl auf AMD, als auch auf NVIDIA-Hardware kein Problem darstellen. Beide teilen einem Buffer immer erst dann Speicher auf der Grafikkarte zu wenn dieser dort das erste mal verwendet wird. AMD dokumentiert dies explizit in seinem AMD APP Programming Guide. NVIDIA geht in seiner GPU Computing Documentation zwar nicht explizit auf diese Problematik ein, Beiträge in den Foren von NVIDIA und Khronos dokumentieren aber dieses Verhalten. Bedenken sollte man allerdings, dass man, um von diesem Verhalten zu profitieren, CL_MEM_COPY_HOST_PTR nicht verwenden darf. AMDs Programming Guide empfiehlt explizit einen gemeinsamen Context für alle Devices zu verwenden, da dies programmiertechnisch die einfacherere Lösung ist. Es wird aber auch eingestanden, dass ein Context pro Device deutlich flexibler ist. Dies ist beispielsweise die einzige Möglichkeit CPUs mit NVIDIA-Grafikkarten zu kombinieren. Die Flexibilität mehrere Contexte hat allerdings ihren Preis. So ist es nicht möglich die Ausführung zwischen mehreren Contexten über Events zu synchronisieren. Die OpenCL-Spezifikation weist explizit darauf hin, dass ein Befehl in einer Workqueue immer nur auf Events welche zum gleichen Context gehören warten kann. Prinzipiel kann diese Beschränkung mithilfe von Event Callbacks und User Events umgangen werden, dies ist aber auch mit einem höheren Aufwand verbunden. Außerdem sollte man auch immer bedenken, dass Buffer welche ausschließlich auf der CPU verwendet werden mit CL_MEM_ALLOC_HOST_PTR oder CL_MEM_USE_HOST_PTR initialisiert werden sollten um unnötiges kopieren der Daten zu vermeiden.

Liebe Berliner, geht Wählen!

Heute sind Wahlen in Berlin. Und da nichts besser wird wenn man seine Stimmer nicht erhebt, möchte ich hier noch einmal alle zum Gang zur Wahlurne aufrufen. Ihr müsst ja gar nicht gut finden was SDP/CDU/FDP und Grüne machen. Im Zweifelsfall gibt es immer noch genug „Einthemenparteien“ welche einen Standpunkt vertreten den ihr für wichtig haltet. Die mögen zwar mit eurer Stimme nicht ins Parlament einziehen, aber ihr gebt damit dem vertretenen Thema Gewicht, denn jede Partei, für die es nicht zur Mehrheit gereicht hat, hätte diese Stimme natürlich gerne gehabt. Außerdem gibt es dieses Jahr in Berlin, wie unter anderem bei Fefe berichtet, auch noch eine recht kuriose Möglichkeit das Parlament zu verkleinern und damit Steuergelder zu sparen. Also, auch wenn Blumentop eigentlich zur Bundestagswahl 2009 sang, gültig ist immer noch: „Beweg dein Arsch!“;

Spaß mit gcc und geschützten Leerzeichen

Wenn ich von meinem Mac aus in einem Vim auf einem anderen Rechner programmiere beschwert sich gcc öfter mal über folgendes und weigert sich die Datei zu kompilieren:

some_source.cpp:519:2: error: stray ‘\302’ in program
some_source.cpp:519:2: error: stray ‘\240’ in program

Wie man in node.js URLs auf Funktionen abbildet

Das "Hallo, Welt!" in node.js ist es einen kleinen Webserver zu bauen der eben diesen Text zurück gibt. Doch was, wenn man nicht nur eine Seite zurückgeben möchte? Eine kleine Funktion hilft abhängig von der eingegebenen URL verschiedenen JavaScript-Funktionen aufzurufen.

Das "Hallo, Welt!" in node.js ist es einen kleinen Webserver zu bauen der eben diesen Text zurück gibt. Doch was, wenn man nicht nur eine Seite zurückgeben möchte? Eine kleine Funktion hilft abhängig von der eingegebenen URL verschiedenen JavaScript-Funktionen aufzurufen. In der Doku zu node.js geht hervor, dass das Request-Objekt die URL im Attribut url enthält. Der einfachste Weg URLs auf Funktionen abzubilden ist ein Objekt zu erstellen welches einfach die Pfade als Attributsname und die dazugehörigen Funktionen als Attributswerte verwendet. Dann können wir einfach direkt am Objekt die URL aufrufen. Das abbildende Objekt könnte so aussehen: var url_mapping = {  '/': printIndex,  '/index.html': printIndex} Die Funktion printIndex kann so aussehen: // Ok, not really an index, but works.var printIndex = function(req, res) {  res.writeHead(200, {'Content-Type': 'text/plain'});  res.end('Hello, World!\n');} Die Abbildung wird dann wie folgt implementiert: mapped = url_mappings[req.url];if (mapped) {  mapped(req, res);} else {  console.log(req.url + ' has not been mapped');  invalidURL(req, res);} Der Code nutzt aus, dass wir in JavaScript dynamisch auf Werte eines Objektes zugreifen können und undefined zurückbekommen wenn der Wert im Objekt nicht gesetzt ist. Theoretisch könnte es hier ein Problem geben da JavaScript Objekte immer ein paar eigene Attribute besitzen, wie z.B. die Funktion hasOwnProperty, aber da die URL immer mit einem Schrägstrich beginnt, kann man mit keinem dieser Werte kollidieren, es sei denn irgendeine JavaScript-Bibliothek beginnt irgendwann wahnsinnigerweise Objekte mit solchen Werten anzureichern. Mit der einfachen Funktion können wir zwar schon URLs auf Funktionen abbilden, oft möchte man aber eine ganze Klasse von URLs auf eine Funktion abbilden. Mithilfe des URL-Moduls könnte man zwar die URL noch um den Query-Teil bereinigen, aber wenn man alle URLs die mit einem bestimmten String anfangen, oder gar die einem bestimmten regulären Ausdruck entsprechen, abgebildet werden sollen kommen wir mit dem bisherigen Ansatz nicht weiter. Um auch diesen Fall abzuhandeln können wir einen Array nutzen der Objekte enthält die jeweils ein Muster auf eine Funktion abbildet: var pattern_mapping = [  { pattern: '/echo/', mapped: echo },  { pattern: /^\/regexp/, mapped: printMatch }]; Möchten wir die richtige Funktion für eine URL finden so müssen alle Muster im Array durchprobieren. Da JavaScripts typeof-Operator leider reguläre Ausdrücke nicht eindeutig identifiziert akzeptieren wir alles welches die für unseren Test benötigte Methode aufweist: for (i = 0; !mapped && i < pattern_mappings.length; i = i + 1) {  pattern = pattern_mappings[i].pattern;  console.log('Testing pattern ' + i + ': ' + pattern + ' [' + typeof(pattern) + ']');  if( typeof(pattern) === 'string' && req.url.slice(0, pattern.length) === pattern ) {    mapped = pattern_mappings[i].mapped;  } else if ( pattern.test && typeof(pattern.test) === 'function' && pattern.test(req.url) ) {    // we can only assume it's a regexp, as typeof is not clear on it,    // but if it has a test function...    mapped = pattern_mappings[i].mapped;  }} Das ganze kann man natürlich noch beliebig aufbohren. Eine naheliegende Verbesserung wäre der aufgerufenen Funktion noch als dritten Parameter das abgebildete Muster zu übergeben. Ohne weitere Verbesserungen sieht die komplette Funktion so aus: function(req, res, url_mappings, pattern_mappings) {  // Forward decleration of variables as recommended by Crockford  var i;  var mapped;   console.log('Request url: ' + req.url);   // check whether the url has a direct mapping  mapped = url_mappings[req.url];  if (mapped) {    mapped(req, res);  } else {    // url did not match any of the direct mappingss    // check whether it matches anny of the patterns    for (i = 0; !mapped && i < pattern_mappings.length; i = i + 1) {      pattern = pattern_mappings[i].pattern;      console.log('Testing pattern ' + i + ': ' + pattern + ' [' + typeof(pattern) + ']');      if( typeof(pattern) === 'string' && req.url.slice(0, pattern.length) === pattern ) {        mapped = pattern_mappings[i].mapped;      } else if ( pattern.test && typeof(pattern.test) === 'function' && pattern.test(req.url) ) {        // we can only assume it's a regexp, as typeof is not clear on it,        // but if it has a test function...        mapped = pattern_mappings[i].mapped;      }    }    if (mapped) {      mapped(req, res);    } else {      console.log(req.url + ' has not been mapped');      invalidURL(req, res);    }  }} Zum einfacheren rumspielen mit dem Code gibt es das Beispiel als Datei: path.js_.txt

Mediatomb vs. PS3 vs. Opera

Seit ich meine PS3 von meinem Heimserver aus mit Videos, Musik und Bildern versorge hatte ich immer wieder das Problem, dass die PS3 scheinbar zufällig das dafür genutzte Mediatomb mal sah, und mal nicht sah. Inzwischen konnte ich das Problem auf eine Wechselwirkung mit Opera Unite zurückführen. Schaltet man diese Funktionalität auf allen Rechnern im LAN aus verschwindet das Problem.

Seiten

Sollten dir die Artikel auf dieser Seite gefallen und du Bitcoin für ein interessantes Experiment halten, so schicke doch eine kleine Spende an 14pQyjx5EFQCwPBkXMTz5nTcfPsnjHmWqA.

Subscribe to Marix.org RSS