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);
}

Thursday, June 19, 2014

Devtools installation on Centos

Default gcc fails to compile linux 3.x source code. It required me to upgrade
devtools for CentOS.

cd /etc/yum.repos.d

wget http://people.centos.org/tru/devtools-2/devtools-2.repo

yum install devtoolset-2-gcc
yum install devtoolset-2-binutils


export PATH=/opt/rh/.....:$PATH

check gcc -v which should be higher then default gcc version.