Thursday, June 18, 2015

Intro to Go Programming Package Creation

Go tools requires code organization in specific way for easy build, deploy your go code. The following section describes the process.

1) Create a specific directory $HOME/mygo
2) Set the environment variable GOPATH=$HOME/mygo
3) Create a unique namespace mkdir $GOPATH/src/github.com/nf

Develop your code inside the namespace

mkdir $GOPATH/src/github.com/nf/hello
cd $GOPATH/src/github.com/nf/hello
>> write your hello.go

build and install your hello.go with go install command in the current directory the binary will be installed in $GOPATH/bin directory

Lets create our own package to by used by other go program such as hello.go

mkdir $GOPATH/src/github.com/nf/string
cd $GOPATH/src/github.com/nf/string/string.go
>> write your string.go

================
package string

func Reverse(s string) string {
        b := []byte(s)
        for i:=0; i < len(s)/2; i++ {
                j := len(s)-i-1
                ch := b[i]
                b[i] = b[j]
                b[j] = ch
        }
        return (string(b))

}
===============
run go install in the string directory to create package string the output string.a will appear in 
$GOPATH/pkg/linux_amd64/github.com/nf/string.a 

Now lets use our string package in our hello.go

cd $GOPATH/src/github.com/nf/hello.go

===============
package main

import (
        "fmt"
        "github.com/nf/string"
)

func main() {
        fmt.Println(string.Reverse("Hello World!!"))
}
================

build the hello.go with go install

Cool!!

Let's write test program to test the package
cd $GOPATH/src/github.com/nf/string/
vi string_test.go


======================
package string

import "testing"

func Test(t *testing.T) {
        var tests = []struct {
                s, want string
        } {
                {"Backward", "drawkcaB"},
                {"Hello, # %", "% # ,olleH"},
                {"", ""},
        }

        for _, c:= range tests {
                got := Reverse(c.s)
                if got != c.want {
                        t.Errorf("Reverse(%q) == %q, want %q", c.s, got, c.want)
                }
        }

}

===============

run go test (If no error great, else fix the issue)

Sunday, May 31, 2015

Visualize CPU on your System

Visual Representation of CPU on your system
=============================
$ lstopo





Learn about your CPU (Via lscpu)
=====================
$ lscpu

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    2
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Stepping:              3
CPU MHz:               3201.250
BogoMIPS:              6385.14
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              8192K
NUMA node0 CPU(s):     0-7

Monday, February 2, 2015

get_user_pages example

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mm.h>

static  struct  class *sample_class;

static int sample_open(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "%s\n", __FUNCTION__);
        return (0);
}

static int sample_release(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "%s\n", __FUNCTION__);
        return (0);

}

static ssize_t  sample_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
        int     res;
        struct  page *page;
        char    *myaddr;
        printk(KERN_INFO "%s\n", __FUNCTION__);
        down_read(&current->mm->mmap_sem);
        res = get_user_pages(current, current->mm,
                (unsigned long)buf,
                1,
                1,              
                1,
                &page,
                NULL);
        if (res) {
                printk(KERN_INFO "Got mmaped.\n");
                myaddr = kmap(page);
                printk(KERN_INFO "%s\n", myaddr);
                strcpy(myaddr, "Mohan");
                page_cache_release(page);
        }
        up_read(&current->mm->mmap_sem);
        return (0);
}

static struct   file_operations sample_ops = {
        .owner  = THIS_MODULE,
        .open   = sample_open,
        .release = sample_release,
        .write  = sample_write
};

static int __init sample_init(void)
{
        int ret;
        ret = register_chrdev(42, "Sample", &sample_ops);
        sample_class = class_create(THIS_MODULE, "Sample");
        device_create(sample_class, NULL, MKDEV(42, 0), NULL, "Sample");
        return (ret);
}

static void __exit sample_exit(void)
{
        device_destroy(sample_class, MKDEV(42, 0));
        class_destroy(sample_class);
        unregister_chrdev(42, "Sample");
}

module_init(sample_init);
module_exit(sample_exit);

MODULE_LICENSE("GPL");





======

obj-m += sample.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
        $(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
        $(MAKE) -C $(KDIR) M=$(PWD) clean


========


#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
        int fd;
        char *ptr;
        fd = open("/dev/Sample", O_RDWR);
        if (fd < 0) {
                perror("error");
        }
        posix_memalign((void **)&ptr, 4096, 4096);
        memcpy(ptr, "krishna", strlen("krishna"));  //Write String to Driver
        write(fd, ptr, 4096);
        printf("data is %s\n", ptr);   //Read Data from Driver
        close(fd);
}

Tuesday, October 28, 2014

mongodb storage engine

Download mongodb and rocksdb
 
$ git clone https://github.com/mongodb/mongo.git   
$ git clone https://github.com/facebook/rocksdb.git
 
Build Rocksdb
 


$ cd rocksdb
$ make static_lib
$ cp librocksdb.a /usr/local/lib
$ cp -r include/* /usr/local/include
 
Build mongodb
 

$ cd ..
$ cd mongo
 
For MAC 
$ scons --rocksdb --rocksdb --libc++ --osx-version-min-10.7 mongo mongod
 
For Linux
 
$ scons --rocksdb --rocksdb mongo mongod
 
Kickoff parallel build with -j <n>
 
 
Experiment with mongod/rocksdb in local build directory without installing 
 
$ mkdir ./data
$ ./mongod  --dbpath ./data --storageEngine=rocksExperiment 
 
 
Ready to interact with mongodb with rocksdb storage engine
 
$ ./mongo
 
 
Sample Program to Interface with RocksDB
========================================
 
#include <iostream>
#include "rocksdb/db.h"

using namespace std;

int
main()
{
    std::string     value;
    std::string     key1, key2;
    rocksdb::DB* db;
    rocksdb::Options options;
    options.create_if_missing = true;
    rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);

    cout << status.ToString() + "\n";
    key1 = string("foo");
    value = string("data");

    rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
    if (s.ok()) {
        s = db->Put(rocksdb::WriteOptions(), key1, value);
        cout << "Key Found " + key1 + " Value " + value + "\n";
    } else {
        cout << "Key Not Found Insert Key\n";
        s = db->Put(rocksdb::WriteOptions(), key1, value);
        if (s.ok()) {
            s = db->Get(rocksdb::ReadOptions(), key1, &value);
            if (s.ok()) {
                cout << "Key Found " + key1 + " Value " + value + "\n";
            }
        }
    }
    //db->Delete(rocksdb::WriteOptions(), key1);
    /* Close DB */
    delete db;
}

Compile Sample Program
======================
g++ -std=c++0x rocks_db.cpp -lrocksdb -lpthread  -lz

 

Friday, September 5, 2014

CPUID Instructions

CPUID instructions are complex instructions. It can be used to extract processor properties. CPUID instruction is a serializing instruction, i.e when executed, all concurrent, speculative and pipelined executions are stopped.

Information such as Processor, Cache/TLB, Cache Parameters, Performance Monitoring, L2 Cache information can be retrieved from user-space.


Refer to Intel Developer Instruction Manual.

typedef struct cpuid {
        uint32_t        eax;
        uint32_t        ebx;
        uint32_t        ecx;
        uint32_t        edx;
} cpuid_t;

static cpuid_t
get_cpu_id(uint32_t id)
{
        cpuid_t cpu;
        asm("mov %%ebx, %%esi\n\t"
                "cpuid\n\t"
                "xchg %%esi, %%ebx"
                : "=a"  (cpu.eax),
                  "=S"  (cpu.ebx),
                  "=c"  (cpu.ecx),
                  "=d"  (cpu.edx)
                : "a" (id)
        );
        return (cpu);
}

int
main()
{
        cpuid_t cpu;
        char    name[100];

        /* issue CPUID 0 instruction to read CPU information */
        cpu = get_cpu_id(0);
        printf("cpu.eax is %d\n", cpu.eax);
        sprintf(n, "%.4s%.4s%.4s\n", (char *)&cpu.ebx, (char *)&cpu.ecx, (char *)&cpu.edx);

        printf("processor name is %s\n", name);

        cpu = get_cpu_id(1);
        printf("Processor Type is %x\n", (cpu.eax & 0x00003000));
        printf("Family Type is %x\n", (cpu.eax & 0x00000F00) >> 8);


        cpu = get_cpu_id(0x80000008);
        printf("cache info phyMemory size %x\n", 1 << (cpu.eax & 0x0000000F));
        printf("cache info virtMemory %x\n", 1 << (cpu.eax >> 8));

}

Monday, August 25, 2014

DPDK playground

Compile DPDK library
===============
make config T=x86_64-native-linuxapp-gcc
or
make config T=i686-native-linuxapp-gcc

make

/* With No Huge Page*/
build/app/testpmd -c f -n 1  -w 02:00.0 --no-huge

or

/* With Huge Page */
build/app/testpmd -c f -n 1  -w 02:00.0


To view the current setting using the /proc entry for huge page
# cat /proc/sys/vm/nr_hugepages 0


To set the number of huge pages using /proc entry:
# echo 5 > /proc/sys/vm/nr_hugepages

Mount hugetlbfs
 

#mount -t hugetlbfs nodev /mnt/huge/


Build Applications
============

make install T=x86_64-native-linuxapp-gcc

Sunday, June 29, 2014

LinkedList in Kernel Example

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>

struct  object_list {
        int     id;
        struct list_head list;
};

LIST_HEAD(obj_context);

static int __init
my_init(void)
{
        struct object_list *obj;
        obj = kmalloc(sizeof(struct object_list), GFP_KERNEL);
        obj->id = 5;

        list_add(&obj->list, &obj_context);

        return (0);
}

static void __exit
my_fini(void)
{
        struct  list_head *pos, *q;

        list_for_each_safe(pos, q, &obj_context) {
                struct object_list *obj = NULL;
                obj = list_entry(pos, struct object_list, list);
                list_del(pos);
                kfree(obj);
        }
        return;
}

module_init(my_init);
module_exit(my_fini);

MODULE_DESCRIPTION("Sample Code");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Krishna Mohan");


I was an working on porting driver in user space and didn't want to write my own implementation. I copied the code from the kernel and tried in userspace and as expected it worked fine. I'm doing the same for other function which i will keep posting on my blog.
#include <stdio.h>
#include <stdlib.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

struct list_head {
        struct list_head *next, *prev;
};

struct nvme_ns {
        struct list_head list;
        int num;
};

static inline void INIT_LIST_HEAD(struct list_head *list)
{
        list->next = list;
        list->prev = list;
}

static inline void __list_add(struct list_head *_new,
                              struct list_head *prev,
                              struct list_head *next)
{
        next->prev = _new;
        _new->next = next;
        _new->prev = prev;
        prev->next = _new;
}


static inline void list_add_tail(struct list_head *_new, struct list_head *head)
{
        __list_add(_new, head->prev, head);
}

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type, member) ); })

#define list_entry(ptr, type, member)   \
        container_of(ptr, type, member)

#define list_for_each_entry(pos, head, member)                          \
        for (pos = list_entry((head)->next, typeof(*pos), member);      \
                &pos->member != (head);                                 \
                pos = list_entry(pos->member.next, typeof(*pos), member))

#define list_for_each_entry_safe(pos, n, head, member)                  \
        for (pos = list_entry((head)->next, typeof(*pos), member),      \
                n = list_entry(pos->member.next, typeof(*pos), member); \
                &pos->member != (head);                                 \
                pos = n, n = list_entry(n->member.next, typeof(*n), member))


static inline void __list_del(struct list_head *prev, struct list_head *next)
{
        next->prev = prev;
        prev->next = next;
}

#define LIST_POISON1    ((void *) 0x00100100)
#define LIST_POISON2    ((void *) 0x00200200)

static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = (struct list_head *) LIST_POISON1;
        entry->prev = (struct list_head *) LIST_POISON2;
}


int
main()
{
        struct list_head name;
        struct  nvme_ns *ns, *next;

        INIT_LIST_HEAD(&name);

        ns = malloc(sizeof(struct nvme_ns));
        printf("alloc %p\n", ns);
        ns->num = 1;

        list_add_tail(&ns->list, &name);

        ns = malloc(sizeof(struct nvme_ns));
        printf("alloc %p\n", ns);
        ns->num = 2;
        list_add_tail(&ns->list, &name);

        list_for_each_entry(ns, &name, list)
                printf("num is %d\n", ns->num);

        list_for_each_entry_safe(ns, next, &name, list) {
                list_del(&ns->list);
                printf("free %p\n", ns);
                free(ns);
        }
        return (0);
}