Pages

Showing posts with label LinuxKernel. Show all posts
Showing posts with label LinuxKernel. Show all posts

Tuesday, June 13, 2017

NVMe: Officially faster for emulated controllers!

The Doorbell Buffer Config command

When I last wrote about NVMe, the feature to improve NVMe performance over emulated environments was just a living discussion and a work in progress patch. However, it has now been officially released in the NVMe Specification Revision 1.3 under the name "Doorbell Buffer Config command", along with an implementation that is already in the mainline Linux Kernel! \o/

You can already feel the difference in performance if you compile Kernel 4.12-rc1 (or later) and run it over a virtual machine hosted on Google Compute Engine. Google actually updated their hypervisor as soon as the feature was ratified by the NVMe working group, even before it was publicly released.

There were very few changes from the original proposal, I.e. opcodes, return values and now fancy names; the buffers (as described in my last post) are now called Shadow Doorbell and EventIdx buffers.

In short, the first one mimics the Doorbell registers in memory, allowing the emulated controller to fetch the Doorbell value when convenient instead of waiting for the Doorbell register to be written. For its part, the EventIdx provides a hint given by the emulated controller to tell the host if the Doorbell register needs to be updated (in case the emulated controller is not fetching the Doorbell value from the Shadow Doorbell buffer). You can check section 7.13 of the specification for an example of usage.

Results

The following test results were obtained in a machine of type n1-standard-4 (4 vCPUs, 15 GB memory) at Google Cloud Engine platform with Kernel 4.12.0-rc5 using the following command:

$ sudo fio --time_based --name=benchmark --runtime=30 \
--filename=/dev/nvme0n1 --nrfiles=1 --ioengine=libaio --iodepth=32 \
--direct=1 --invalidate=1 --verify=0 --verify_fatal=0 --numjobs=1 \
--rw=randread --blocksize=4k --randrepeat=0

Results (in Input/Ouput Operations per Second):
Without Shadow Doorbell and EventIdx buffers: 43.9K IOPS
With Shadow Doorbell and EventIdx buffers: 184K IOPS
Gain ~= 4 times

Screenshot - Without Shadow Doorbell and EventIdx buffers

Screenshot - With Shadow Doorbell and EventIdx buffers

Enjoy your enhanced numbers of IOPS! :D

Wednesday, May 3, 2017

Collabora Contributions to Linux Kernel 4.11

Linux Kernel v4.11 was released, and 9 different Collabora developers contributed a total of 44 patches, an increase of 5 patches from version 4.10. The majority of Collabora's work this time was around fixes and clean ups in the DRM. In addition to our contributions as authors, Collabora also added 22 Reviewed-by tags for patches reviewed by our engineers. You can learn more information about the v4.11 merge window in LWN.net's extensive coverage: part 1, part 2 and part 3.

Now here is a look at the specific changes made by Collaborans. To begin with, Enric Balletbo fixed an issue and improved documentation of IIO regarding sensors and also added support for several buses and peripherals for the Toby-Churchill SL50 board. Romain Perier added an ASoC machine driver for Rockchip rk3288-based boards that have an HDMI and analog audio output, and also added support for slave mode in the Everest Semi ES8328 audio codec, while including ES8388 as a compatible device in the ES8328's codec driver.

For his part, Tomeu Vizoso fixed the sink display error in DRM EDID when no deep color is available for Rotel RSX-1058 and also fixed several issues and code cleanups regarding CRC in DRM and integrated the new CRC debugfs API in i915. Gabriel Krisman Bertazi, who wrote a great article recently on tracing the user space and Operating System interactions, made several improvements to DRM by adding documentation, cleaning up the code and fixing several issues, including allowing QXL build when FBDEV_EMULATION is disabled.

Lastly, Daniel Stone, Collabora's Graphics Lead, fixed an important issue in DRM regarding the use of Atomic State in legacy ioctls, while Fabien Lahoudere cleaned up the code for the Epson RTC removing an unnecessary spinlock, and Robert Foss fixed a copy of uninitialized memory in Ethernet qed code.

Here is the complete list of Collabora contributions:

Daniel Stone (1):

Enric Balletbo i Serra (10):

Fabien Lahoudere (1):

Gabriel Krisman Bertazi (19):

Gustavo Padovan (1):

Martyn Welch (1):

Romain Perier (4):

Tomeu Vizoso (6):

Robert Foss (1):

Reviewed-by:

Gustavo Padovan (8):

Emil Velikov (5):

Gabriel Krisman Bertazi (3):

Robert Foss (3):

Daniel Stone (2):

Tomeu Vizoso (1):

Tuesday, August 23, 2016

Increased performance of emulated NVMe devices

Nowadays, in Google Cloud Engine (GCE), it is possible to attach a local SSD with the NVMe interface to your virtual machine. Unfortunately, you only get a good number of iops (input/output operations per second) if you instantiate a machine with nvme-backports-debian-7-wheezy image; other available distributions on GCE will have a lower number of iops.

It turns out that Google's Virtual Machine Monitor (aka Hypervisor) implements a custom NVMe command that allows it to increase up to 4 times the number of  iops (note: this is from what I've tested so far, but it seems to be possible to get up to 5 times faster according to the original commit message; check the  Technical Details sessions to see how this is possible), however the kernel you use needs to support it and this is not yet the case with the mainline kernel.

This is not exclusive to GCE as Google released a patch not only to the kernel  but also to the qemu and is available here.

Collabora has been helping update, refactor and review the patches to the Linux Kernel to send it upstream, however since this is not yet an official nvme standard, it shouldn't be merged into Kernel mainline, as its specification may still receive changes.

Seeing as it considerably increases performance, the feature is in the process of being discussed and proposed to the NVMe workgroup with Collabora's help.
While the nvmexpress.org seems interested in adding an official extension to stardarize it, as published in the mailing list, nothing has been defined yet, as this is a very recent discussion and it can take up to a year to be ratified by the NVMe workgroup.

So, for the time being, you can get a more recent version of the patch and install the driver yourself here: https://git.collabora.com/cgit/user/koike/linux.git/log/?h=nvme/dev

How it works?

Technical details

 

The NVMe interface basicaly works with command queues. The drive writes a command in a region known to both (driver and device controller) and then updates the tail of the queue, writting to an MMIO register called doorbell.

In an environment with several guest OSes on top of a VMM sharing a resource, communication between the guest OS and the real device is usually trapped by the VMM. As an MMIO is usually a syncronous acces to the device, it means that every MMIO access will cause a trap.

Example of emulated device in the VMM
The main idea here is to decrease the number of traps to the VMM by reducing the number of writtes to the doorbells.

This is achieved in two ways:
    1) Batching; or
    2) Letting the VMM pull the current doorbell value when it is already in execution.

The first one is easy, we can wait X commands to be written in the queue to ring the doorbell.
The second one is a bit more complicated. The guest OS needs to inform the emulated device in the VMM where it can pull the doorbell values, and the emulated NVMe device needs to inform the guest OS that it can restart the counter of X.

This is what this new feature does:
It adds a new command in the NVMe interface where the driver can send to the NVMe device controller two memory buffers:
1) A buffer where the real doorbell values are: Instead of writting to the MMIO  doorbell, the driver writtes the value in this buffer; and
2) Another buffer with a hint from the controller about how many commands the driver can write in the queue without ringing the doorbell.


The exact technical details may still change in the future, especially on how to properly implement the second item above. It is also very likely that Google's patches won't be compliant with the future ratified standard.

For the time being though, you can use the Collabora tree. Please let me know if you have any comments/feedback!

Tuesday, August 4, 2015

[Outreachy Status Log] Scaler implementation

The implementation of the scaler node (which increases the size of the received image by a multiplier) is done and available in my github account: https://github.com/helen-fornazier/opw-staging

The debayer filter (from the previous Outreachy Status Log post) is also available there.

The scaler still doesn't work if the received image is in bayer format, I'll let this to a future patch.

The next patch will allow changes in the pad format by user space as the frame size and enumerate the supported pixel formats by the ioctls. I already have a sketch of this code but I need to test it a little more.

Monday, August 3, 2015

[Outreachy Status Log] Debayer implementation

What is a bayer format

The sensor of a camera is composed my many color sensors, each of this color sensors just capture a single color. Thus a sensor may be composed with many color sensors in the order Red and Green in the odd lines and Green and Blue in the even lines for example:

|Red Sensor.....| Green Sensor.|Red Sensor.....| Green Sensor.|
|Green Sensor..| Blue Sensor...|Green Sensor..| Blue Sensor...|
|Red Sensor.....| Green Sensor.|Red Sensor.....| Green Sensor.|
|Green Sensor..| Blue Sensor...|Green Sensor..| Blue Sensor...|

We say it's a RGGB bayer format. We could have any combinations of these color sensors as GRBG (for Green and Read in the odd lines and Blue and Green in the even lines), BGGR, GBRG, GRBG, etc.
Usually our eye are more sensible to green, that is why we are te double of green sensors compared to the other color components.

Here is a Bayer format image, 64x64 RGGB:



If you look closely you can notice that in the odd lines we have only Red and Green and in the even lines we have Green and Blue.

Thus, the camera process the results of each color sensor to build the image we are used to. And we will simulate this filter in out VIMC (Virtual media controler, yes, it was rename from VMC to VIMC).

Simple debayer algorithm

To get each color component of each pixel we will calculate the mean of the color components around a given color sensor, i.e. a Blue color sensor is inside a 3x3 square (or mean window):

R G R
G B G
R G R

The Red component will be the mean of all four Red components in this square, the Green component will be the man of all four Green component in this square and the Blue is the value read from the Blue sensor being evaluated.

The mean window can be any SxS size, where S is an odd value to allow the pixel being evaluated to be in the center of the square.

Results

Debayer, windows size 3x3, image size 64x64

Debayer, windows size 5x5, image size 64x64


Debayer, windows size 11x11, image size 64x64

Code structure - the pix map table

In the implementation I have a table which describes the order:


With this table I am able to write a generic code to all the bayer orders.

I am still cleaning up this code, it will be available in my github soon

Sunday, July 19, 2015

Linux Kernel: memory corruption - debug tricks

Note: This post is meant to help you debug a memory corruption if you are building your own kernel from source.

The symptoms:


If you see one of the following errors in your in your dmesg log:

* BUG: unable to handle kernel paging request at 7f45402d
* invalid opcode: 0000 [#1] SMP
* general protection fault: 0000 [#1] SMP
* BUG: unable to handle kernel NULL pointer dereference at 0000000000000258

Then you probably have a memory corruption somewhere.

In my case, I didn't get these errors at first. I was adding objects to a list by calling list_add_tail(my_list, my_obj) and verifying that list_empty(my_list) was returning false as expected (and it was). But latter in the code when I called list_empty(my_list) again, it was returning true, and in nowhere in my code I was removing objects from the list.

Weird behaviors that doesn't make sense probably are due to memory corruption. When I started simplifying the code to isolate the problem, I start getting the errors above in the dmesg log.

Where it is happening:


When you have an error, you get a log message in dmesg like:

We will be looking at 2 infos there:
1) The IP (instruction pointer) address in the 2nd line
2) The call trace at line 23rd

The IP

In the 2nd line of this log, we have the instruction pointer address, it is the address the computer was executing that generated the error.

In this example, the IP is ffffffff817c69f0, then we can find where in the code this address corresponds to using the addr2line tool:

Where the path_to_your_kernel_tree is the path to the kernel code where you downloaded it (where you do make && make install)
The vmlinux file is the uncompressed version of the Linux image (it is created when you do make)

Note: if it doesn't work, check if your make menuconfig if your kernel is compiled with DEBUG flag

But this technique won't work if the corresponding address is not part of the kernel core code (if it was an error caused by some module, as we will see in the call trace section).

The call trace

In the log above, line 23rd, it means that the function devres_remove was called by devres_destroy, which was called by devm_kfree, which was called by vmc_cap_destroy and so on.

Now suppose that the vmc_cap_destroy function call devm_kfree in many places and you want to know exactly which one has triggered the bug. Lets do this in 2 steps:

1) Get the offset in the code section of the function using nm:
nm is a tool to get the offset of a symbol in a section:

In this example, the offset of the vmc_cap_destroy function is 0x680

2) Get the file and the line using addr2line:
In line 27th we have: vmc_cap_destroy+0x40, where the 0x40 is the offset inside the vmc_cap_destroy function where the code execution would return if the call to devm_kfree hadn't triggered the bug.

So lets add the function offset we found in the previous step with the offset inside the function: 0x680 + 0x40 = 0x6c0

And now we use the addr2line with the compile module.ko to find out where is it:

Then the buggy devm_kfree call is the first one just before the line 396 in file vmc-capture.c

Enable debug prints:


Besides the techniques above, you can enable the debug level prints in the dmesg log:

sudo sh -c "echo 8 > /proc/sys/kernel/printk"

If this doesn't work, check if the DYNAMIC_DEBUG flag is enabled in your menuconfig, if so, then check the next section about Dynamic debug.

In the case of a module that I was testing (the vivid module), I needed to change the vivid_debug parameter:

We can do this when we start the module:

sudo modprobe vivid vivid_debug=8

Or changing the parameter while its already running:

sudo sh -c "echo -n 0 > sys/module/vivid/parameters/vivid_debug"


Dynamic debug:

If your kernel is compiled with DYNAMIC_DEBUG flag, then changing the printk level probably won't enable the debug prints in the dmesg log.

Lets say the module we are working is called media, lets add it into the kernel:

sudo modprobe media

And now we will enable all the debug prints in the media module by sending 'module media +p' to the dynamic_debug/control file:

If you look at the dynamic_debug/control file content (as we did above) you can see the "=p" which means that the prints in those lines are enabled.

To disable the prints, we send 'module media -p' to the dynamic_debug/control file:

If you look at the dynamic_debug/control file content again you can see the "=_" which means that the prints in those lines are disabled.

Enabling a specific print

Instead of enabling all the debug prints of the entire module, we can enable all the prints on a specific file, or we can specify a file and a line:

$ sudo sh -c "echo -n 'file media-entity.c +p' > /sys/kernel/debug/dynamic_debug/control"

$ sudo sh -c "echo -n 'file media-entity.c line 301 +p' > /sys/kernel/debug/dynamic_debug/control"

Read dmesg log continuously


Instead of calling dmesg every time to check the log, you can do:

$ tail -f /var/log/kern.log

and the log will be printed continuously.

Saturday, July 18, 2015

[Outreachy Status Log] First VMC version to the linux-media mailing list

I just sent the first version of the Virtual Media Controller driver to the linux-media mailing list, now I am waiting more reviews from other developers.

You can check the code in my github account https://github.com/helen-fornazier/opw-staging in branch vmc/review/video-pipe.

Now I'll setup the Test Patter Generator (tpg) from the Vivid driver to be a separated module, as this code will be reused in the Vmc as well to generate the colored bar image instead of the grey one.

Sunday, July 12, 2015

[Outreachy Status Log] Generating a colored bar image

It has being a month since the last status log. Here is status of my progress:

- The architecture of the code has changed a lot since the last log. Several patches reviews were made between me and my mentor.

- The code now supports link validation, e.g, you can't turn on the streaming if the formats between subdevs are not compatible.

- It is more modular and easy to adapt to a dynamic topology configuration.

- Several bugs were corrected.

- The test pattern generator was imported from the vivid driver and now the code generates a non-grey image:



The next patch series will contain this test patter generator and the user will be able to configure the format of the image.

The next step is to work in a debayer block.

Saturday, June 20, 2015

Linux Kernel: How to start contributing

Is really not that dificult to start contributing with a small patch to the Linux kernel, my first patch was to correct a missing space between binary operands (i==j) -> (i == j) that I found running a script available in the kernel code, I ran something like:
perl scripts/checkpatch.pl -f path_to_some_driver_folder/ | less
And I found the coding style problem. But first you need to download and compile the kernel.

This is going to be a short post with really useful links.

Things you will need to know to start:
* GIT
* C programing

1) Download, compile and install a kernel compiled by your self: follow these instructions
Note1: I takes a really long time: check my posts about CCache and Icecc to speed up compilation.
Note2: Consider to setup a virtual machine if you plan to develop something that can break your system.

2) Setup more tools, find a coding style problem and prepare a patch and submit it: follow these instructions
Note1: the above link tells you to not send the patch to the Linux list. You need to check who are the maintainers of the file you are modifying by running the script:
perl scripts/get_maintainer.pl <path_to_your_patch_generated_with_git_format.patch>
Or:
perl scripts/get_maintainer.pl -f <file_that_you_modified>
Or:
git show HEAD | perl scripts/get_maintainer.pl
This will get you a list of people and emails, so you can send your patch to all of them in CC.

Note2: Do interleaved/bottom-posting when replying emails. Don't put your reply before quoted original message as Gmail does by default.

3) Joing the #kernelnewbies irc channel on freenode, its a chat so you can make newbie questions.
If you don't know how to do it, download the HexChat irc client (sudo apt-get install hexchat), go to menu->Network List, look for freenode and click on connect. Then wait a window to show up asking you which channels you would like to connect and type #kernelnewbies, or type /join kernelnewbies in the freenode chat window.

How to start working in something more interesting then fixing coding style:

4) Start reading the Linux Device Drivers (LDD3) Book, its free and you can read online.
You will learn the basis in writing a driver. The book comes with some code to test the drivers it implement but most of it is not compatible with the last kernel version. If you are stuck and can not compile a driver provided by the LDD3, leave me a comment and I can help.

5) Be aware of the Documentation folder inside the Linux kernel tree, it has a lot of docs about the internal API and software architecture. Sometimes it is hard to find which file should you be reading (just ask in the #kernelnewbies).

6) Where to go now: Check the http://kernelnewbies.org/ site, it is meant for newbies :)

Check this ilustrated guide about Linux Kernel development from another Outreachy intern

I am working on a video4linux driver. If you are interested in learning how to write a driver for your camera, follow my posts :)

Sunday, June 14, 2015

[Outreachy Status Log] Third week - Basic video pipe with a capture and sensor node

This is a resume in what I've been working on.
There is no much content in this post if you are looking for useful information to your project. I am posting more useful information under the Nerd category.
Check my first Outreachy post to know how they are organized.


This week I worked in a first pipeline skeleton as first proposed here.

This is the output of the topology from my code:


The sensors generate a simple grey image for now from a kthread, and it is being propagated to the Raw capture nodes. The other nodes (debayer, input and scaler) don't have any inteligent yet.
It is possible to view the generated (grey) image from tools such as qv4l2

The sensors and capture device codes still need to improve.

This week I sent this patch series to my mentor. After my mentor's feedback and the appropriate patch corrections, the next step is implementing a basic debayer, scaler and input intelligence.

You can check the development of this in my github Linux Kernel Fork branch vmc/devel/video-pipe

Monday, June 8, 2015

Compiling a single Linux Kernel module inside the Kernel tree

I recently find out a faster way to compile a single module in the Linux Kernel tree thanks to this post:

What I was doing before was taking much more time:

Or a pure make -j5, even if I had already compiled my Kernel once and just modified one module, was taking me ~5 minutes. So each tiny test I made (like changing a the contents of a string) was taking me that long, now it takes some seconds using the make modules SUBDIRS=path/to/module command \o/

To update the module I just copy the .ko to the right place:

It usually works if you made a simple change in the code. Or you can use the SUBDIRS too: