bowerick: Serialization Convenience, Command Line Helpers, and To-dos

In my previous post, I introduced bowerick for easing simple Message-oriented Middleware (MoM) tasks with Clojure (and Java). In this post, I will introduce some more features of bowerick in more detail. In addition, I will discuss some of the things that, in my opinion, need further improvement.

The outline of this post is as follows:

  • Motivation (Skip this if you are only interested in the technical parts.)
  • Serialization Convenience
  • Command Line Helpers
    • Broker
    • Client
  • To-dos
    • Modularity
    • Logging
  • Concluding Remarks

Motivation

In this part, I discuss my motivation for implementing the features that I will cover in this post. You can safely skip this part if you are more interested in the technical parts. However, I want to provide a bit of context, just in case it could be helpful or interesting.

As I mentioned in my previous post, I started with bowerick (or more precisely its predecessor) in scope of some research I did. Some of my needs at that time were that I wanted to ease and speed-up the prototype development and to keep my prototypes, experiments, etc. as self-contained as reasonably possible. In this scope, the intent of bowerick was to bundle the MoM related functionality and to provide easily usable abstractions on an API-level.

During my research, I experimented a bit with different ways of serializing the data that was sent via the MoM. In this context, I also considered not only the actual serialization but also compression/decompression.

Thanks to many available nice libraries, various serialization and compression methods can be easily used. However, while the implementation overhead of using a single library is quite small, the effort accumulates with the amount of libraries and serialization/compression methods that are used. Furthermore, in order to reduce the probability of errors in my experiments, I used unit tests for assessing the functionality.

Besides providing easily usable abstractions on an API-level, e.g., for serialization as mentioned above, I also considered the use of the MoM broker as another part that could be improved for easing usage and development. For this, I developed a simple command line helper runnable for easily running a simple MoM broker. After finishing my dissertation etc., I also found some time to add experimental “client” support as well.

Serialization Convenience

The default way for creating producers and consumers with bowerick is via the create-producer respectively create-consumer functions in the bowerick.jms namespace. By default the created producers/consumers use the serialization/de-serialization mechanisms of the underlying JMS transport implementation, such as ActiveMQ OpenWire.

However, depending on the used transport, the default serialization mechanisms on the producer side may not be suited for all data types. For the producer, I implemented a fallback serialization that currently defaults to serialization to UTF-8 encoded JSON via Cheshire. On the consumer side, however, it is not easily possible to identify the type of serialization that was used just based on the byte array payload (I refrained from implementing a smarter consumer as it is not possible to reliably distinguish between meta-data that identifies a serialization method and potential valid payload data that should be forwarded as is.).

In order to allow the easy use of other serialization and also compression mechanisms, I added various convenience functions for creating more specialized producers/consumers. Currently, these functions are (in the bowerick.jms namespace):

For create-nippy-producer, below, I give some examples of possible Nippy options for compressing the data, which are set via the “normal” Nippy options map. For now, do not worry about the “1” argument. I will write about that in another post.

  • (def lz4-prod (create-nippy-producer “tcp://broker:61616” “/topic/foo” 1 {:compressor taoensso.nippy/lz4-compressor}))
  • (def snappy-prod (create-nippy-producer “tcp://broker:61616” “/topic/foo” 1 {:compressor taoensso.nippy/snappy-compressor}))
  • (def lzma2-prod (create-nippy-producer “tcp://broker:61616” “/topic/foo” 1 {:compressor taoensso.nippy/lzma2-compressor}))

For create-nippy-consumer, no options need to be set as Nippy can identify the compression mechanisms for decompression.

From the point of interoperability and as I am primarily working with “basic” data structures, such as maps or sequences, my current favorite serialization mechanism is create-json-producer / create-json-consumer. This offers excellent interoperability across different messaging transports/protocols, such as OpenWire, STOMP, or MQTT, and also across programming languages. I plan to write about using multiple transports in a later post.

Command Line Helpers

In the following, I will describe simple broker and client related command line helper functionality provided by bowerick.

Broker

The main idea for the broker command line helper was to have an easy way for starting a simple broker instance. In the simplest form, a broker can be started with a bowerick stand-alone jar file as follows:

java -jar target/bowerick-1.99.6-standalone.jar

By default, bowerick listens sets up an OpenWire transport connector that listens on 127.0.0.1:61616. In the following listing, an example for specifying the transport/protocol is shown. Please note the additional escaped quotation marks.

java -jar target/bowerick-1.99.6-standalone.jar --url "\"stomp://127.0.0.1:61617\""

bowerick also offers convenience functionality for leveraging ActiveMQs support for multiple transports/protocols. I plan to write more about multiple transports/protocols in another blog post. For now, with respect to the broker command line helper, in the following listing, the syntax for starting a broker with multiple transports/protocols is shown.

java -jar target/bowerick-1.99.6-standalone.jar --url "[\"tcp://127.0.0.1:61616\" \"stomp://127.0.0.1:61617\"]"

Note that the list of transports is just a Clojure vector of strings in which each string defines one transport/protocol. Again, note the escaped quotation marks.

Client

While the broker command line helper essentially only provides a way for conveniently starting a MoM broker instance, the client command line helper is intended to allow more dynamic interaction. Thus, the main part of the client-side command line helper is an interactive command line interface (CLI), which uses my cli4clj library for creating the interactive CLI.

Currently, the client command line helper is in an early stage and I consider it as an experiment in progress. Use cases of the client command line helper can be, e.g.:

  • simple debugging
  • or serving as a playground tool for easily playing with a MoM.

In the following, I will provide a brief usage example for the client command line helper. For this example, I assume that a JMS broker is running that listens for incoming OpenWire connections on tcp://127.0.0.1:61616. Such a broker instance can be, e.g., started with the bowerick broker command line helper as follows:

java -jar target/bowerick-1.99.6-standalone.jar

The following listening shows the start of the bowerick client command line helper and the prompt of the interactive CLI:

java -jar target/bowerick-1.99.6-standalone.jar --client
...
bowerick#

In order to receive data from a destination, the “receive” command can be used as follows:

bowerick# receive tcp://localhost:61616:/topic/foo.bar
Creating JSON consumer: tcp://localhost:61616 /topic/foo.bar 1
Creating consumer: tcp://localhost:61616 /topic/foo.bar
Creating connection.
Creating destination. Type: topic Name: foo.bar
Set up consumer for: tcp://localhost:61616:/topic/foo.bar
bowerick#

The “receive” command creates a consumer that is connected to the specified broker and destination. I will discuss the “URL format” a bit more later. The consumer that is set up with the “receive” command will print the received data to stdout.

In order to send data to a destination, the “send” command can be used as follows:

bowerick# send tcp://localhost:61616:/topic/foo.bar baz
Creating JSON producer: tcp://localhost:61616 /topic/foo.bar 1
Creating producer: tcp://localhost:61616 /topic/foo.bar
Creating connection.
Creating destination. Type: topic Name: foo.bar
Sending: tcp://localhost:61616:/topic/foo.bar <- baz bowerick# Received: tcp://localhost:61616:/topic/foo.bar ->
"baz"

bowerick#

Please note that the listing also shows the reception output of the consumer that was previously set up with the “receive” command. Due to the current way of how the output is printed, the output of the consumer is simply printed on top of the prompt, which looks not so nice, in my opinion.

Also note that the producer instances created with the “send” command are cached. For subsequent invocations of “send” with an earlier used URL the producer initialization is omitted:

bowerick# send tcp://localhost:61616:/topic/foo.bar baz
Sending: tcp://localhost:61616:/topic/foo.bar <- baz bowerick# Received: tcp://localhost:61616:/topic/foo.bar ->
"baz"

bowerick#

Furthermore, the interactive CLI supports Clojure data types like maps or vectors. The default serialization mechanism uses JSON serialization via Cheshire mentioned above:

bowerick# send tcp://localhost:61616:/topic/foo.bar {"a" "string", :b [1 7 0 1]}
Sending: tcp://localhost:61616:/topic/foo.bar <- {"a" "string", :b [1 7 0 1]} bowerick# Received: tcp://localhost:61616:/topic/foo.bar ->
{"a" "string", "b" [1 7 0 1]}

bowerick#

Note that one effect of the JSON default serialization is that a keyword “:b” is changed to the string “b”.

The destination-url format is: ://

::/[topic,queue]/. can be, e.g.: tcp, udp, stomp, ssl, or stomp+ssl.
is the IP address or name of the broker. is the port number on which the broker listens. is the name of the topic/queue to which the data will be sent.

I borrowed “:/” for separating the broker part from the destination part from the way SSH SCP URLs are expressed. However, I am not yet fully convinced that this is the right way to do it. Anyway, as this is just a detail of the experimental client CLI, I do not see any major problems for changing this in the future.

To-dos

As I mentioned in this and in my previous post, bowerick and its predecessor project are a result of the needs I had during some of my experiments. Hence, I more or less “selfishly” focused primarily on the needs I had. However, with the rework I started since the fork from the original project, I also tried to get bowerick in a shape that makes it more useful for others.

Still, as this is currently a single person spare time project, there are quite a number of things that can be improved. In this section, I will briefly discuss some of these aspects.

Modularity

bowerick bundles a lot of different functionality, such as different MoM transports, serialization mechanisms, and compression methods. Thus, it has a lot of dependencies and the resulting uberjar files are pretty large.

If only a subset of the functionality offered by bowerick is used, many dependencies and space occupied in the uberjar file will be redundant. In order to counteract these issues, one potential improvement of bowerick could be to modularize bowerick into smaller better defined sub-modules.

I realize that splitting up bowerick into sub-modules is the inverse of the original intent to combine functionality and provide easily usable abstractions. However, maybe there are possibilities to keep the ease of use that is currently offered and still split bowerick into better defined sub-modules.

Logging

The logging in bowerick is currently just done via printing messages to stdout and stderr.
It is not possible to specify logging targets, such as files, or log levels to adjust the verbosity of the output. This is clearly not what one would expect in a more productive environment.

Furthermore, bowericks dependencies further complicate the situation as there may be different potentially incompatible logging mechanisms pulled in. Admittedly, I didn’t even have the time to get a complete overview of all logging mechanisms that are pulled in by the dependencies.

Consequently, providing more sophisticated logging in bowerick and to harmonizing the logging of dependencies could be another potential improvement.

Concluding Remarks

I hope that bowerick is useful for some of you. As you can see in the history, I tried to keep the dependencies as up to date as reasonably possible, up to now. Furthermore, I hope that the test-driven development approach with a high test coverage and the continuous testing and integration help to keep bowerick updated and to improve its quality. Nonetheless, there is the caveat that bowerick is a single person spare time project, for now. Constructive feedback, suggestions, etc. are always appreciated.

Posted in bowerick, Libs. | Tagged , , , , | Leave a comment

bowerick: Easing Simple Message-oriented Middleware Tasks with Clojure (and Java)

TL;DR

The aim of bowerick is to ease simple Message-oriented Middleware (MoM) tasks with Clojure and, to some extent, with Java. The general functionality that is offered by bowerick is:

  • Creating message producers and sending messages.
  • Creating message consumers and receiving messages.
  • Programmatically running embedded MoM brokers.

bowerick also offers more advanced features. However, I want to keep this post concise. Hence, I focus on the most fundamental features.

bowerick supports the following protocols for clients and servers: OpenWire (UDP & TCP), STOMP, STOMP via WebSocket, and MQTT. All protocols except OpenWire UDP can also be used via encrypted connections (SSL/TLS).

History

In this section, I want to briefly summarize the history of bowerick. I hope that having a bit of historical context will help you to determine whether bowerick fits your needs or not. If you are more interested in the technical aspects, just skip this section and continue reading with the next section.

I initially started the development of the project (clj-jms-activemq-toolkit) that gave rise to bowerick during my PhD thesis and employment as researcher at the Frankfurt University of Applied Sciences. Hence, you will find the copyright of the university in various places.

Back then, my main need was to have something that helped me with some experiments that I did as part of my research work and for my PhD thesis. Essentially, I wanted to have abstractions to ease simple MoM tasks and I also implemented prototypes for evaluating some ideas which partially continue in bowerick.

bowerick started as a fork of clj-jms-activemq-toolkit. From my perspective, bowerick is the direct continuation of clj-jms-activemq-toolkit, for which I was the only contributor anyway. The intention of the fork is to signal the changed scope of bowerick, from a loose collection of JMS tooling and prototypes to something, hopefully, more evolved.

However, please be aware that bowerick is still a toy project of mine. Future development is primarily driven by “fun aspects”. Nonetheless, I hope to provide a solid project that is helpful and easy and fun to use as you can see, e.g., in the continuous integration, API documentation, and test coverage efforts. Since the fork of bowerick, I also performed extensive re-factoring and further development in order to improve code and capabilities for which I did not have the time while I was writing my dissertation.

Brief Introduction

The main aim of this post is to provide a brief introduction of bowerick. Hence, I will focus on the fundamental features.

I think the most illustrative way to show the fundamental functionality (producer, consumer, embedded broker) is to show an example code snippet. In the following listing, a corresponding example is shown:

; Can also be run in: lein repl
(require '[bowerick.jms :as jms])
(def url "tcp://127.0.0.1:61616")
(def destination "/topic/my.test.topic")
; Create an embedded broker.
(def brkr (jms/start-broker url))
; Create a consumer that prints the received data.
(def consumer (jms/create-json-consumer url destination (fn [data] (println "Received:" data))))
; Create a producer ...
(def producer (jms/create-json-producer url destination))
; ... and send some data.
(producer "foo")
; nilReceived: foo
(producer '(1 7 0 1))
; nilReceived: (1 7 0 1)
(jms/close producer)
(jms/close consumer)
(jms/stop brkr)
; (quit)

As embedded broker and for the OpenWire protocol, bowerick uses Apache ActiveMQ. For the other supported protocols, bowerick uses different other libraries.

In the following listing, examples for URLs of supported protocols are shown:

;
; Encrypted
;
; OpenWire via TCP
(def url "ssl://127.0.0.1:61616")
; STOMP via TCP
(def url "stomp+ssl://127.0.0.1:61616")
; STOMP via WebSocket
(def url "wss://127.0.0.1:61616")
; MQTT via TCP
(def url "mqtt+ssl://127.0.0.1:61616")
;
; Unencrypted
;
; OpenWire via TCP
(def url "tcp://127.0.0.1:61616")
; OpenWire via UDP
(def url "udp://127.0.0.1:61616")
; STOMP via TCP
(def url "stomp://127.0.0.1:61616")
; STOMP via WebSocket
(def url "ws://127.0.0.1:61616")
; MQTT via TCP
(def url "mqtt://127.0.0.1:61616")

As bowerick is the continuation of clj-jms-activemq-toolkit, the versioning continues where the original project stopped. Currently, I think that the re-worked API etc. is pretty much stable. Still, the current version is 1.99.x, which indicates its state as a sort of preliminary version before the 2.x release. However, I think that the, at time of writing, latest version 1.99.5 is a pretty good candidate for the final 2.0.0 release.

I hope that you consider bowerick useful. I intend to post more details about bowerick and more of its features in future posts. Feedback and comments are always appreciated.

Posted in Announcements, bowerick, Libs. | Tagged , , , , , | 1 Comment

Panoramic Photos, Heidelberg & Dielheim

I used a trip this year to Dielheim and Heidelberg, as opportunity to try to make some more panoramic photos. As usual, I took the individual photos with my smartphone and used Huggin as stitcher.

The first two panoramas were taken from the castle in Heidelberg. The first panorama was taken in the direction of the old town of Heidelberg. The second panorama shows a view more in the direction of the Neckar river.

20160707_031 - 20160707_047_scaled

20160707_088 - 20160707_098_scaled

The last panorama shows a view of a landscape in Dielheim.

20160709_079 - 20160709_090_scaled

Posted in Misc. | Tagged , | Leave a comment

cli4clj 1.2.0 Released

This is a brief post to announce the release of version 1.2.0 of cli4clj, a small library for easing the creation of interactive command line interfaces (CLIs). The most noteworthy changes in this version are:

  • Addition of a run-time setting to print full traces of exceptions instead of just printing the exception message.
  • Fallback to String representation for elements that would otherwise cause a RuntimeException due to invalid tokens.
  • Addition of a “print” command for the example application.

The “enable-trace true” run-time setting, which defaults to “false”, enables printing of the full traces of exceptions instead of just printing the exception message. In the following listing a somewhat shortened example is shown:

cli# enable-trace false
print-exception-trace is set to: false
cli# d 1 0
Divide by zero
cli# enable-trace true
print-exception-trace is set to: true
cli# d 1 0
java.lang.ArithmeticException: Divide by zero
 at clojure.lang.Numbers.divide (Numbers.java:158)
 cli4clj.example$divide.invokeStatic (example.clj:21)
 cli4clj.example$divide.invoke (example.clj:20)
 ...

Some input values, e.g., “/foo/bar” would cause an exception due to an invalid token. In version 1.2.0, I added a fallback, that returns the String representation in such cases instead of failing with an exception. The fallback can be disabled by setting the cli4clj configuration setting “:invalid-token-to-string” in the options map to false.

Last but not least, a “print” function was added to the example application. The print function serves two purposes. It pretty prints its arguments including the type of the first argument. This is, e.g., intended for getting an understanding of what data types cli4clj uses for what input. In addition, the print command shows the use of optional arguments.

Some known issues and things that I may improve in the future, as my time permits it, are, e.g.: the full stack trace is printed to stdout instead of stderr because of some strange behavior I had here on my development machine. The setting for switching between full stack trace vs. short exception message output uses a global atom var, for now. I plan to refactor that in future.

I hope that you consider these changes useful. As usual, feedback and comments are always appreciated.

Posted in cli4clj, Libs. | Tagged , , , | Leave a comment

cli4clj 1.1.0 Released

This is a brief post to announce the release of cli4clj, a small library for easing the creation of interactive command line interfaces (CLIs), version 1.1.0. The most noteworthy changes in version 1.1.0 are:

  • Updated dependencies
  • Moved the testing helper functions from cli4clj.cli to cli4clj.cli-tests.

I did the latter change in order to improve the organization of the code and to make it easier for users to identify which functions/macros are useful for which purpose. However, if you are already using the testing helper functionality, you need to change the imported namespace from cli4clj.cli to cli4clj.cli-tests.

As usual, constructive criticism, comments, and feedback are highly appreciated.

PS: Shortly after writing this, I realized that I did not update to the latest stable jline2 version, which is 2.14.2. cli4clj version 1.1.1 fixes this.

 

Posted in cli4clj, Libs. | Tagged , , , | Leave a comment

Performance of “Method Calls” on “Clojure Objects”

tl;dr

There are various ways for implementing objects or object-like constructs with Clojure. Besides differences with respect to implementation aspects, these ways also differ with respect to their performance. In this post, I write about the results of some simple benchmarks for evaluating the performance of some approaches that I could find in books and the Internet. If you are just interested in the overview, just scroll down to the performance overview plot that is located close to the end of this post.

Introduction and Motivation

For modelling data, I actually like generic data types such as maps, vectors, etc. and Clojures functionality for dealing with these generic data types very much. However, in certain circumstances, I like to use “classical objects” in which I encapsulate certain elements and that provide methods for interacting with the encapsulated entities.

An example of a situation in which I like to use “classical objects” is when a resource, e.g. a connection, has to be created and various operations need to be performed with this resource. Examples of such resources are: network sockets, JMS connections, or database connections. Examples of operations that I want to perform with these resources are: transmitting data, acquiring performance statistics, or closing the resource.

While there are already various posts etc. about the implementation or engineering aspects related to using object-like functionality in Clojure, I missed a comparison of the corresponding performance aspects. I think that, to certain extend, the choice which approach is used or if object-like behavior is used at all is a matter of taste. However, taking the aforementioned examples, such as communication or database connections, performance is an important aspect.

In the remainder of this post, I first outline the ways for implementing object-like behavior that were analyzed. Afterwards, the results of the performance benchmarks are shown.

Ways for Implementing Object(-like) Functionality in Clojure

The intention of this section is not to provide an in-depth discussion of ways for implementing object-like functionality in Clojure. The aim is rather to provide an overview of the working principles of the analyzed methods.

defprotocol and deftype/defrecord

The use of defprotocol in conjunction with deftype/defrecord is, e.g., discussed in:
https://dzone.com/articles/object-oriented-clojure
http://thinkrelevance.com/blog/2013/11/07/when-should-you-use-clojures-object-oriented-features

In the following listing, extracts for an example of this approach using defprotocol and defrecord are shown. The working principles for deftype are similar.

(defprotocol WithConnection
 (send [this data])
 (close [this]
 ...))

(defrecord ConnectionWrapper [resource]
 WithConnection
 (send [_ data] (.send resource data))
 (close [_] (.close resource))
 IFn
 (invoke [this data] (send this data)))

(defn create-connection
 [...]
 (let [resource (...)]
 (->ConnectionWrapper resource)))

(...
 (let [c (create-connection ...)]
 ; Send via "send" method defined in WithConnection.
 (send c "my data")
 ; By implementing IFn the object itself can also be used as a function.
 (c "my data")
 (close c)))

In the example, a “resource” is wrapped in an object and the object provides methods for interacting with the resource. In addition to the definition of the “send” method, the example also shows that a record can implement IFn such that the corresponding objects can be used as functions.

Closure with Functions in a Map

In “The Joy of Clojure” by Michael Fogus and Chris Houser, Manning, 2011, pp. 139-140, an example of implementing object-like functionality via closures and a returned map with functions is given. In “Let over Lambda” by Doug Hoyte, 2008, pp. 32-33, a similar way for implementing object-like functionality by using a closure and returning a list of multiple functions is given.

In the following listing, extracts for an example of this approach are shown:

(defn create-connection
 [...]
 (let [resource (...)]
 {:send (fn [arg] (.send resource arg))
 :close (fn [] (.close resource))
 ...}))

(defn send
 [conn arg]
 ((conn :send) arg))

(defn close
 [conn]
 ((conn :close)))

(...
 (let [c (create-connection ...)]
 (send c "my data")
 (close c)))

The example follows the same usage scenario as the previously given scenario for defrecord. In order to ease the method calls, additional functions are used to hide the map-based implications. Instead of functions, macros could be used as well but I just show functions here for illustration purposes.

Closure with Function Dispatch based on Keywords

In http://pramode.net/clojure/2010/05/26/creating-objects-in-clojure/ and “Clojure in Action” by Amit Rathore, Manning, 2012, pp. 326-328, closures and function dispatch based on keywords are used for mimicking object-like behavior. While I have to confess that I also used similar implementations in some of my older projects, I would not use this approach anymore. Seen from today’s perspective, I consider this as a rather complicated and inflexible way for achieving object-like functionality. Furthermore, the results of the performance evaluation shown in this post also indicate that, depending on the actual setting, the performance is inferior compared to the other approaches.

In the following, an example for this way of achieving object-like functionality is shown:

(defn create-connection
 [...]
 (let [resource (...)]
 (fn [arg]
 (condp =
 :close (.close resource)
 ...
 (.send resource arg)))))

(defn close
 [conn]
 (conn :close))

(...
 (let [c (create-connection ...)]
 (c "my data")
 (close c))

The example follows the same usage scenario as the other two examples.

Performance Result

In the following, at first, the tested scenarios are outlined. Subsequently, plots showing the results of the benchmarks are shown and described briefly. Afterwards, the procedure of how the benchmarks were performed is summarized and links to the benchmark code and raw data are given. The entire benchmark code including the post-processing scripts is available as Open Source Software, so you can give it a shot on your own.

Tested Scenarios

Below, the tested scenarios are outlined.
For more details, please have a look at the source code for which links are given below.

The tested scenarios can be roughly distinguished as follows:

  • baseline measurements for providing a basis for comparisons,
  • measurements for the approach based on keywords and condp (condp-x),
  • measurements for the map-based approach (map-x),
  • and measurements for the deftype and defrecord based approaches (record-x and type-x).

The baseline measurements tested the following scenarios:

  • adding two constants (baseline-0-add),
  • calling an fn returning a constant (baseline-1-fn-const),
  • calling an fn with an argument returning the argument as-is (baseline-2-fn-arg),
  • calling an fn that adds a constant value to the fn argument (baseline-3-fn-add-arg),
  • and calling an fn that uses a closure to add a pre-defined value to the fn argument (baseline-4-fn-add-closure).

For the condp-based scenario, the number of tests of the condp expression were varied. The actual operation that was to be performed was in the final default clause of the condp expression. The value x in the scenario description condp-x matches the number of tests that preceded the final default clause.

For the map-based tests, the number of key-value pairs in the map was varied. The value x in map-x is the number of key-value pairs that were added in addition to the actual entry that was to be executed. For map-x, the map was used as fn and the keyword as argument: (m :kw). For map-rev-x, the keyword was used as fn and the map as argument: (:kw m).

For the defrecord and deftype based approaches, the following situations were considered:

  • calling the fn defined in the implemented protocol as function and passing the object etc. as arguments: (f obj arg)
  • calling the fn defined in the implemented protocol as method of the object: (.f obj arg)
  • calling the object as fn (The type/record implements IFn.) and using the fn-way for forwarding the call to the actual processing functionality.
  • calling the object as fn (The type/record implements IFn.) and using the method-way for forwarding the call to the actual processing functionality.
  • calling an fn that wasadded by extending the protocol.

Result Plots

In the figure below, an overview of the absolute execution time is shown. Please not that the y-axis uses a logarithmic scale. The shown values are the mean values as reported by Criterium. In addition, the standard deviation is shown with error bars. However, due to the small standard deviation, these error bars are hardly visible.

2016-04-12_20-55_colin_FreeBSD_out_1

In the figure below, an overview of the relative execution time of the same result data as shown in the previous figure is shown. The result of scenario “baseline-4-fn-add-closure” was used as reference for the calculation of the relative values. Please note that the y-axis is linear and that the y-axis range was purposely chosen to focus on the majority of results at the expense of accepting that some values could not be fit on the plot.

2016-04-12_20-55_colin_FreeBSD_out_2

Benchmark Procedure and Source Code

For the execution of the benchmarks, criterium (https://github.com/hugoduncan/criterium) was used. Criterium automatically takes care of warm-up, repeated measurement execution, statistics calculation etc. Please note: even though the source code contains “quick-bench” right now, the benchmarks were done with “bench” (In the meantime, I changed the default to “bench”.).

Each benchmark scenario was implemented as separate Clojure test and the tests were all run via Leiningen. The source code of the benchmarks is available as Open Source Software: https://github.com/ruedigergad/clojure-method-call-benchmark/

Concluding Remarks

The evaluated scenarios were purposely chosen to be comparably simple. There may also be many more variations that could be assessed, such as other ways for implementing object-like behavior, the impact of type hints and reflection, or permutations of these aspects. However, for me, I found these results already quite interesting and I hope that the results or the benchmark code itself are useful for others as well. Comments and suggestions are always appreciated.

 

 

 

Posted in Misc., Other Software, Snippets | Tagged , | 2 Comments

Note to self: get information about the camera in SailfishOS

This is just a brief note to self about getting information about the camera in SailfishOS with v4l-utils.
This post primarily consists of a list of some commands that showed me some, hopefully useful, information and the corresponding output.
Maybe this is useful for someone else as well.

First of all, one has to install v4l-utils.
This can be done as follows:

zypper ar http://repo.merproject.org/obs/home:/nielnielsen/sailfish_latest_armv7hl/home:nielnielsen.repo
zypper ref home_nielnielsen
pkcon install v4l-utils

At first, outputs that were taken on a OnePlus One smartphone running SailfishOS are shown (Later on, I also put the corresponding outputs from the original Jolla phone.).
The kernel with which I took the data from the OnePlus One was:

[root@localhost ~]# uname -a
Linux localhost 3.4.67-cyanogenmod-gb4c3166-dirty #4 SMP PREEMPT Mon Jan 4 19:14:07 UTC 2016 armv7l armv7l armv7l GNU/Linux

[root@localhost ~]# ll /dev/video
total 0
lrwxrwxrwx 1 root root 12 Feb 27 13:07 venus_dec -&gt; /dev/video32
lrwxrwxrwx 1 root root 12 Feb 27 13:07 venus_enc -&gt; /dev/video33

Below are commands that provided some information about the video subsystem including their output:

[root@localhost nemo]# v4l2-ctl --list-devices
VIDIOC_QUERYCAP: failed: Invalid argument
VIDIOC_QUERYCAP: failed: Invalid argument
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Invalid argument
VIDIOC_QUERYCAP: failed: Invalid argument
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
msm_vdec_8974 ():
	/dev/video32
	/dev/video33
	/dev/video34
	/dev/video35
	/dev/video38
	/dev/v4l-subdev6
	/dev/v4l-subdev0
	/dev/v4l-subdev1
	/dev/v4l-subdev2
	/dev/v4l-subdev3
	/dev/v4l-subdev4
	/dev/v4l-subdev5
	/dev/v4l-subdev7
	/dev/v4l-subdev8
	/dev/v4l-subdev9
	/dev/v4l-subdev10
	/dev/v4l-subdev11
	/dev/v4l-subdev12
	/dev/v4l-subdev13
	/dev/v4l-subdev14
	/dev/v4l-subdev15
	/dev/v4l-subdev16
	/dev/v4l-subdev17

���� (c���pKͶ):
	/dev/video1
	/dev/video2

Failed to open /dev/video0: Device or resource busy

[root@localhost nemo]# v4l2-ctl -D -d /dev/video32
Driver Info (not using libv4l2):
	Driver name   : msm_vidc_driver
	Card type     : msm_vdec_8974
	Bus info      : 
	Driver version: 0.0.1
	Capabilities  : 0x04003000
		Video Capture Multiplanar
		Video Output Multiplanar
		Streaming
[root@localhost nemo]# v4l2-ctl -D -d /dev/video33
Driver Info (not using libv4l2):
	Driver name   : msm_vidc_driver
	Card type     : msm_venc_8974
	Bus info      : 
	Driver version: 0.0.1
	Capabilities  : 0x04003000
		Video Capture Multiplanar
		Video Output Multiplanar
		Streaming
[root@localhost nemo]# v4l2-ctl -D -d /dev/video38
Driver Info (not using libv4l2):
	Driver name   : wifi-display
	Card type     : msm
	Bus info      : 
	Driver version: 0.0.1
	Capabilities  : 0x04000001
		Video Capture
		Streaming

[root@localhost nemo]# v4l2-ctl -V -d /dev/video32
VIDIOC_G_FMT: failed: Resource temporarily unavailable
[root@localhost nemo]# v4l2-ctl -V -d /dev/video33
VIDIOC_G_FMT: failed: Resource temporarily unavailable
[root@localhost nemo]# v4l2-ctl -V -d /dev/video38
Format Video Capture:
	Width/Height  : 1280/720
	Pixel Format  : 'H264'
	Field         : Any
	Bytes per Line: 0
	Size Image    : 1413120
	Colorspace    : Unknown (00000000)

[root@localhost nemo]# v4l2-ctl --list-formats -d /dev/video32     
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture Multiplanar
	Pixel Format: 'NV12'
	Name        : Y/CbCr 4:2:0

[root@localhost nemo]# v4l2-ctl --list-formats -d /dev/video33 
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture Multiplanar
	Pixel Format: 'MPG4'
	Name        : Mpeg4 compressed format

	Index       : 1
	Type        : Video Capture Multiplanar
	Pixel Format: 'H263'
	Name        : H263 compressed format

	Index       : 2
	Type        : Video Capture Multiplanar
	Pixel Format: 'H264'
	Name        : H264 compressed format

	Index       : 3
	Type        : Video Capture Multiplanar
	Pixel Format: 'VP80'
	Name        : VP8 compressed format

[root@localhost nemo]# v4l2-ctl --list-formats -d /dev/video38
ioctl: VIDIOC_ENUM_FMT

[root@localhost ~]# v4l2-sysfs-path -d

Device fd8c0000.qcom,msm-cam:
	video0(video, dev 81:6) v4l-subdev0(v4l subdevice, dev 81:7) v4l-subdev1(v4l subdevice, dev 81:8) v4l-subdev10(v4l subdevice, dev 81:17) v4l-subdev11(v4l subdevice, dev 81:19) v4l-subdev12(v4l subdevice, dev 81:21) v4l-subdev13(v4l subdevice, dev 81:22) v4l-subdev14(v4l subdevice, dev 81:23) v4l-subdev15(v4l subdevice, dev 81:24) v4l-subdev16(v4l subdevice, dev 81:25) v4l-subdev17(v4l subdevice, dev 81:26) v4l-subdev2(v4l subdevice, dev 81:9) v4l-subdev3(v4l subdevice, dev 81:10) v4l-subdev4(v4l subdevice, dev 81:11) v4l-subdev5(v4l subdevice, dev 81:12) v4l-subdev6(v4l subdevice, dev 81:13) v4l-subdev7(v4l subdevice, dev 81:14) v4l-subdev8(v4l subdevice, dev 81:15) v4l-subdev9(v4l subdevice, dev 81:16) 
Device fda0c000.qcom,cci/20.qcom,camera:
	video1(video, dev 81:18) 
Device fda0c000.qcom,cci/6c.qcom,camera:
	video2(video, dev 81:20) 
Device fe02c000:
	hw:0(sound card, dev 0:0) hw:0,0(pcm capture, dev 116:60) hw:0,1(pcm capture, dev 116:58) hw:0,10(pcm capture, dev 116:44) hw:0,11(pcm capture, dev 116:42) hw:0,12(pcm capture, dev 116:40) hw:0,13(pcm capture, dev 116:38) hw:0,14(pcm capture, dev 116:36) hw:0,15(pcm capture, dev 116:34) hw:0,16(pcm capture, dev 116:30) hw:0,17(pcm capture, dev 116:29) hw:0,19(pcm capture, dev 116:26) hw:0,2(pcm capture, dev 116:56) hw:0,20(pcm capture, dev 116:24) hw:0,22(pcm capture, dev 116:21) hw:0,23(pcm capture, dev 116:19) hw:0,24(pcm capture, dev 116:17) hw:0,25(pcm capture, dev 116:15) hw:0,26(pcm capture, dev 116:14) hw:0,27(pcm capture, dev 116:13) hw:0,28(pcm capture, dev 116:12) hw:0,29(pcm capture, dev 116:11) hw:0,3(pcm capture, dev 116:54) hw:0,30(pcm capture, dev 116:10) hw:0,31(pcm capture, dev 116:9) hw:0,32(pcm capture, dev 116:8) hw:0,34(pcm capture, dev 116:6) hw:0,35(pcm capture, dev 116:5) hw:0,36(pcm capture, dev 116:3) hw:0,5(pcm capture, dev 116:51) hw:0,6(pcm capture, dev 116:49) hw:0,8(pcm capture, dev 116:46) hw:0,0(pcm output, dev 116:59) hw:0,1(pcm output, dev 116:57) hw:0,10(pcm output, dev 116:43) hw:0,11(pcm output, dev 116:41) hw:0,12(pcm output, dev 116:39) hw:0,13(pcm output, dev 116:37) hw:0,14(pcm output, dev 116:35) hw:0,15(pcm output, dev 116:31) hw:0,17(pcm output, dev 116:28) hw:0,19(pcm output, dev 116:25) hw:0,2(pcm output, dev 116:55) hw:0,20(pcm output, dev 116:23) hw:0,21(pcm output, dev 116:22) hw:0,22(pcm output, dev 116:20) hw:0,23(pcm output, dev 116:18) hw:0,24(pcm output, dev 116:16) hw:0,3(pcm output, dev 116:53) hw:0,33(pcm output, dev 116:7) hw:0,35(pcm output, dev 116:4) hw:0,36(pcm output, dev 116:2) hw:0,4(pcm output, dev 116:52) hw:0,5(pcm output, dev 116:50) hw:0,6(pcm output, dev 116:48) hw:0,7(pcm output, dev 116:47) hw:0(mixer, dev 116:62) hw:0,1000(sound hardware, dev 116:61) comprC0D18(unknown, dev 116:27) comprC0D9(unknown, dev 116:45) 
Device virtual0:
	video32(video, dev 81:0) 
Device virtual1:
	video33(video, dev 81:1) 
Device virtual2:
	video34(video, dev 81:2) 
Device virtual3:
	video35(video, dev 81:3) 
Device virtual4:
	video38(video, dev 81:4) 
Device virtual5:
	video39(video, dev 81:5) 
Device virtual6:
	timer(sound timer, dev 116:33) 

[root@localhost ~]# v4l2-ctl -P -d /dev/video32
Streaming Parameters Video Capture:
	Frames per second: invalid (0/0)
	Read buffers     : 0
[root@localhost ~]# v4l2-ctl -P -d /dev/video33
Streaming Parameters Video Capture:
	Frames per second: invalid (0/0)
	Read buffers     : 0
[root@localhost ~]# v4l2-ctl -P -d /dev/video38
VIDIOC_G_PARM: failed: Invalid argument

[root@localhost ~]# v4l2-ctl --list-formats-out -d /dev/video32
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Output Multiplanar
	Pixel Format: 'MPG4' (compressed)
	Name        : Mpeg4 compressed format

	Index       : 1
	Type        : Video Output Multiplanar
	Pixel Format: 'MPG2' (compressed)
	Name        : Mpeg2 compressed format

	Index       : 2
	Type        : Video Output Multiplanar
	Pixel Format: 'H263' (compressed)
	Name        : H263 compressed format

	Index       : 3
	Type        : Video Output Multiplanar
	Pixel Format: 'VC1G' (compressed)
	Name        : VC-1 compressed format

	Index       : 4
	Type        : Video Output Multiplanar
	Pixel Format: 'VC1L' (compressed)
	Name        : VC-1 compressed format G

	Index       : 5
	Type        : Video Output Multiplanar
	Pixel Format: 'H264' (compressed)
	Name        : H264 compressed format

	Index       : 6
	Type        : Video Output Multiplanar
	Pixel Format: 'HEVC' (compressed)
	Name        : HEVC compressed format

	Index       : 7
	Type        : Video Output Multiplanar
	Pixel Format: 'HVCH' (compressed)
	Name        : HEVC compressed format

	Index       : 8
	Type        : Video Output Multiplanar
	Pixel Format: 'VP80' (compressed)
	Name        : VP8 compressed format

	Index       : 9
	Type        : Video Output Multiplanar
	Pixel Format: 'DIV3' (compressed)
	Name        : DIVX 311 compressed format

	Index       : 10
	Type        : Video Output Multiplanar
	Pixel Format: 'DIVX' (compressed)
	Name        : DIVX 4/5/6 compressed format

[root@localhost ~]# v4l2-ctl --list-formats-out -d /dev/video33
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Output Multiplanar
	Pixel Format: 'NV12' (compressed)
	Name        : Y/CbCr 4:2:0

	Index       : 1
	Type        : Video Output Multiplanar
	Pixel Format: 'NV21' (compressed)
	Name        : Y/CrCb 4:2:0

[root@localhost ~]# v4l2-ctl --list-formats-out -d /dev/video38
ioctl: VIDIOC_ENUM_FMT

Finally, the corresponding outputs from the original Jolla phone are shown. The kernel used on the Jolla phone was:

[root@Jolla nemo]# uname -a
Linux Jolla 3.4.108.20150901.1 #1 SMP PREEMPT Thu Sep 17 18:32:22 UTC 2015 armv7l armv7l armv7l GNU/Linux

[root@Jolla nemo]# ll /dev/video
ls: cannot access /dev/video: No such file or directory

The output of the video related information is shown below:

[root@localhost nemo]# v4l2-ctl --list-devices
# The device reboots reproducibly and thus no data could be obtained.

root@Jolla nemo]# v4l2-ctl -D -d /dev/video0 
Driver Info (not using libv4l2):
	Driver name   : 
	Card type     : 
	Bus info      : 
	Driver version: 3.4.108
	Capabilities  : 0x04000001
		Video Capture
		Streaming

[root@Jolla nemo]# v4l2-ctl -D -d /dev/video1 
Driver Info (not using libv4l2):
	Driver name   : ov8825
	Card type     : 
	Bus info      : 
	Driver version: 3.4.108
	Capabilities  : 0x04000001
		Video Capture
		Streaming

[root@Jolla nemo]# v4l2-ctl -D -d /dev/video2
Driver Info (not using libv4l2):
	Driver name   : 
	Card type     : 
	Bus info      : 
	Driver version: 3.4.108
	Capabilities  : 0x04000001
		Video Capture
		Streaming

[root@Jolla nemo]# v4l2-ctl -D -d /dev/video3
Driver Info (not using libv4l2):
	Driver name   : ov2675
	Card type     : 
	Bus info      : 
	Driver version: 3.4.108
	Capabilities  : 0x04000001
		Video Capture
		Streaming
[root@Jolla nemo]# v4l2-ctl -D -d /dev/video38
Driver Info (not using libv4l2):
	Driver name   : wifi-display
	Card type     : msm
	Bus info      : 
	Driver version: 0.0.1
	Capabilities  : 0x04000001
		Video Capture
		Streaming
[root@Jolla nemo]# v4l2-ctl -D -d /dev/video39
Failed to open /dev/video39: No such device
[root@Jolla nemo]# v4l2-ctl -D -d /dev/video100
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
/dev/video100: not a v4l2 node

[root@Jolla nemo]# v4l2-ctl -V -d /dev/video0
Format Video Capture:
	Width/Height  : 0/0
	Pixel Format  : ''
	Field         : Any
	Bytes per Line: 0
	Size Image    : 0
	Colorspace    : Unknown (00000000)
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video1
Format Video Capture:
	Width/Height  : 0/0
	Pixel Format  : ''
	Field         : Any
	Bytes per Line: 0
	Size Image    : 0
	Colorspace    : Unknown (00000000)
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video2
Format Video Capture:
	Width/Height  : 0/0
	Pixel Format  : ''
	Field         : Any
	Bytes per Line: 0
	Size Image    : 0
	Colorspace    : Unknown (00000000)
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video3
Format Video Capture:
	Width/Height  : 0/0
	Pixel Format  : ''
	Field         : Any
	Bytes per Line: 0
	Size Image    : 0
	Colorspace    : Unknown (00000000)
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video38
Format Video Capture:
	Width/Height  : 640/480
	Pixel Format  : 'H264'
	Field         : Any
	Bytes per Line: 0
	Size Image    : 462848
	Colorspace    : Unknown (00000000)
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video39
Failed to open /dev/video39: No such device
[root@Jolla nemo]# v4l2-ctl -V -d /dev/video100
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
/dev/video100: not a v4l2 node

[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video0
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture
	Pixel Format: 'NV12'
	Name        : NV12BAYER

	Index       : 1
	Type        : Video Capture
	Pixel Format: 'NV21'
	Name        : NV21BAYER

	Index       : 2
	Type        : Video Capture
	Pixel Format: 'NV16'
	Name        : NV16BAYER

	Index       : 3
	Type        : Video Capture
	Pixel Format: 'NV61'
	Name        : NV61BAYER

	Index       : 4
	Type        : Video Capture
	Pixel Format: 'YM12'
	Name        : YU12BAYER

	Index       : 5
	Type        : Video Capture
	Pixel Format: 'BG10'
	Name        : RAWBAYER

	Index       : 6
	Type        : Video Capture
	Pixel Format: 'STAE'
	Name        : SAEC

	Index       : 7
	Type        : Video Capture
	Pixel Format: 'STWB'
	Name        : SAWB

	Index       : 8
	Type        : Video Capture
	Pixel Format: 'STAF'
	Name        : SAFC

	Index       : 9
	Type        : Video Capture
	Pixel Format: 'IHST'
	Name        : SHST

[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video1
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture
	Pixel Format: 'NV12'
	Name        : NV12BAYER

	Index       : 1
	Type        : Video Capture
	Pixel Format: 'NV21'
	Name        : NV21BAYER

	Index       : 2
	Type        : Video Capture
	Pixel Format: 'NV16'
	Name        : NV16BAYER

	Index       : 3
	Type        : Video Capture
	Pixel Format: 'NV61'
	Name        : NV61BAYER

	Index       : 4
	Type        : Video Capture
	Pixel Format: 'YM12'
	Name        : YU12BAYER

	Index       : 5
	Type        : Video Capture
	Pixel Format: 'BG10'
	Name        : RAWBAYER

	Index       : 6
	Type        : Video Capture
	Pixel Format: 'STAE'
	Name        : SAEC

	Index       : 7
	Type        : Video Capture
	Pixel Format: 'STWB'
	Name        : SAWB

	Index       : 8
	Type        : Video Capture
	Pixel Format: 'STAF'
	Name        : SAFC

	Index       : 9
	Type        : Video Capture
	Pixel Format: 'IHST'
	Name        : SHST

[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video2
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture
	Pixel Format: 'NV12'
	Name        : NV12YUV

	Index       : 1
	Type        : Video Capture
	Pixel Format: 'NV21'
	Name        : NV21YUV

	Index       : 2
	Type        : Video Capture
	Pixel Format: 'YUYV'
	Name        : YUYV

[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video3
ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture
	Pixel Format: 'NV12'
	Name        : NV12YUV

	Index       : 1
	Type        : Video Capture
	Pixel Format: 'NV21'
	Name        : NV21YUV

	Index       : 2
	Type        : Video Capture
	Pixel Format: 'YUYV'
	Name        : YUYV

[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video38
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video39
Failed to open /dev/video39: No such device
[root@Jolla nemo]# v4l2-ctl --list-formats -d /dev/video100
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
/dev/video100: not a v4l2 node

[root@Jolla nemo]# v4l2-sysfs-path -d

Device i2c-4/4-002a:
	video0(video, dev 81:1) 
Device i2c-4/4-0060:
	video2(video, dev 81:4) 
Device platform/msm_cam_server.0:
	video100(video, dev 81:0) v4l-subdev0(v4l subdevice, dev 81:3) v4l-subdev1(v4l subdevice, dev 81:6) v4l-subdev10(v4l subdevice, dev 81:15) v4l-subdev2(v4l subdevice, dev 81:7) v4l-subdev3(v4l subdevice, dev 81:8) v4l-subdev4(v4l subdevice, dev 81:9) v4l-subdev5(v4l subdevice, dev 81:10) v4l-subdev6(v4l subdevice, dev 81:11) v4l-subdev7(v4l subdevice, dev 81:12) v4l-subdev8(v4l subdevice, dev 81:13) v4l-subdev9(v4l subdevice, dev 81:14) 
Device platform/soc-audio.0:
	hw:0(sound card, dev 0:0) hw:0,0(pcm capture, dev 116:27) hw:0,1(pcm capture, dev 116:25) hw:0,10(pcm capture, dev 116:10) hw:0,12(pcm capture, dev 116:7) hw:0,13(pcm capture, dev 116:5) hw:0,14(pcm capture, dev 116:3) hw:0,2(pcm capture, dev 116:23) hw:0,3(pcm capture, dev 116:21) hw:0,5(pcm capture, dev 116:18) hw:0,6(pcm capture, dev 116:16) hw:0,8(pcm capture, dev 116:13) hw:0,9(pcm capture, dev 116:12) hw:0,0(pcm output, dev 116:26) hw:0,1(pcm output, dev 116:24) hw:0,10(pcm output, dev 116:9) hw:0,11(pcm output, dev 116:8) hw:0,12(pcm output, dev 116:6) hw:0,13(pcm output, dev 116:4) hw:0,14(pcm output, dev 116:2) hw:0,2(pcm output, dev 116:22) hw:0,3(pcm output, dev 116:20) hw:0,4(pcm output, dev 116:19) hw:0,5(pcm output, dev 116:17) hw:0,6(pcm output, dev 116:15) hw:0,7(pcm output, dev 116:14) hw:0,9(pcm output, dev 116:11) hw:0(mixer, dev 116:28) 
Device virtual0:
	video1(video, dev 81:2) 
Device virtual1:
	video3(video, dev 81:5) 
Device virtual2:
	video38(video, dev 81:16) 
Device virtual3:
	video39(video, dev 81:17) 
Device virtual4:
	timer(sound timer, dev 116:33) 

[root@Jolla nemo]# v4l2-ctl -P -d /dev/video0
VIDIOC_G_PARM: failed: Invalid argument
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video1
VIDIOC_G_PARM: failed: Invalid argument
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video2
VIDIOC_G_PARM: failed: Invalid argument
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video3
VIDIOC_G_PARM: failed: Invalid argument
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video38
VIDIOC_G_PARM: failed: Invalid argument
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video39
Failed to open /dev/video39: No such device
[root@Jolla nemo]# v4l2-ctl -P -d /dev/video100
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
/dev/video100: not a v4l2 node

[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video0
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video1
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video2
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# 
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video3
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video38
ioctl: VIDIOC_ENUM_FMT
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video39
Failed to open /dev/video39: No such device
[root@Jolla nemo]# v4l2-ctl --list-formats-out -d /dev/video100
VIDIOC_QUERYCAP: failed: Inappropriate ioctl for device
/dev/video100: not a v4l2 node

 

Posted in Misc. | Tagged , , | Leave a comment