<p align="center" style="font-size:40px">
    <b>Sistemas Operacionais</b>
</p>
<p align="center" style="font-size:30px">
    <b>Atividade Bônus 2</b>
</p>
<p align="center" style="font-size:20px">
    <b>07/04/2019</b>
</p>

**NOME:** Batata Frita  
**Matrícula:** 01110000 01101111 01110100 01100001 01110100 01101111

<br>
<br>
<br>
<br>
<br>
<br>
<br>



## Objetivo deste experimento
Foi proposto nesta atividade, fazer dois programas quaisquer na linguagem C:  
1. utilizando funções da biblioteca padrão do sistema (libc: glibc/musl)  
2. utilizando funções de sistema (syscalls)

O objetivo é compará-los e verificar quais dos dois possui a maior eficiência.

## Ambiente utilizado
Para executar este experimento, foi utilizado o seguinte hardware: ``Notebook Dell Latitude 3480 (8GB de memória RAM, processador Intel Core i5-7200 x86_64 2.5GHz)``  
Versão do Kernel: `4.15.0-47-generic`  
Distribuição Linux: ``Ubuntu 18.04``  
Versão do gcc: `7.3.0`  

## Procedimentos adotados
Junto às instruções deste experimento, está o código em C para utilizarmos no teste.  
Para que não seja necessário dois arquivos (um para syscalls, outro para funções da libc) e sim, apenas um arquivo binário, modifiquei o código fonte para ficar da seguinte maneira:  

**./bonus2.c**
```C
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

/*
 * First argument: mode (libc or syscall)
 * Second argument: buffer size
 */

int main(int argc, char *argv[]) {
    char buffer[2000000];
    int i;

    if( !strcmp(argv[1], "syscall") ) {
        i = read(0, &buffer, strtol(argv[2], (char **)NULL, 10));

        while(i > 0) {
            write(1, &buffer, strtol(argv[2], (char **)NULL, 10));
            i = read(0, &buffer, strtol(argv[2], (char **)NULL, 10));
        }
    }
    else if( !strcmp(argv[1], "libc") ) {
        i = fread(&buffer, strtol(argv[2], (char **)NULL, 10), 1, stdin);

        while(i > 0) {
            fwrite(&buffer, strtol(argv[2], (char **)NULL, 10), 1, stdout);
            i = fread(&buffer, strtol(argv[2], (char **)NULL, 10), 1, stdin);
        }
    }
    else {
        printf("%s: Unknown option.\n", argv[0]);
    }

    return 0;
}
```

Para obter o executável, é necessário compilar utilizando o `gcc`:  
`gcc -o bonus2 arquivo.c`

<p style="font-size:14px"><b>Observação</b>: utilizei, também, o <code>clang</code>. Apesar de ser mais rápido, não achei que fosse necessário utilizá-lo como compilador principal para o experimento.
</p>

Essa modificação permite que em único binário, seja executado o teste tanto com syscalls quanto com funções da libc, com o tamanho do buffer desejado. O código deve ser executado desejado seguinde forma:  

- Com funções da libc e com tamanho de buffer 16: `./bonus2 libc 16`
- Com syscalls e com tamanho de buffer 32: `./bonus2 syscall 32`  


De acordo com as instruções, os tamanhos dos buffer que serão usados são: `1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, ..., 1048546`  

Para não ter que executar o binario várias vezes, criei o seguinte script:  

**./iterator.sh**  
```bash
#!/bin/bash

size=1
printf "%s\n" "glibc:"
for i in $(seq 0 20); do

    # clear cache
    sync; echo 3 > /proc/sys/vm/drop_caches
    printf "buffer size: %s - " "$size"

    output=$({ time ./bonus2 libc "$size" < datafile > /dev/null; } 2>&1)
    value_output=$?

    # print only if the above execution was successfull
    if [[ $value_output -eq 1 ]]; then
        echo "$output" | grep real | awk '{ print $2 }'
    fi

    let size=size*2
done

size=1
printf "%s\n" "Syscalls:"
for i in $(seq 0 20); do

    # clear cache
    sync; echo 3 > /proc/sys/vm/drop_caches
    printf "buffer size: %s - " "${size}"

    output=$({ time ./bonus2 syscall "${size}" < datafile > /dev/null; } 2>&1)
    value_output=$?

    # print only if the above execution was successfull
    if [[ $value_output -eq 1 ]]; then
        echo "$output" | grep real | awk '{ print $2 }'
    fi

    let size=size*2
done
```

## Resultados
Com a execução do script acima, obteve-se o seguinte resultado:  

```
glibc:
buffer size: 1 - 0m0,970s
buffer size: 2 - 0m0,951s
buffer size: 4 - 0m0,410s
buffer size: 8 - 0m0,476s
buffer size: 16 - 0m0,450s
buffer size: 32 - 0m0,475s
buffer size: 64 - 0m1,017s
buffer size: 128 - 0m0,776s
buffer size: 256 - 0m0,472s
buffer size: 512 - 0m0,461s
buffer size: 1024 - 0m0,852s
buffer size: 2048 - 0m0,618s
buffer size: 4096 - 0m0,450s
buffer size: 8192 - 0m0,460s
buffer size: 16384 - 0m0,404s
buffer size: 32768 - 0m0,449s
buffer size: 65536 - 0m0,458s
buffer size: 131072 - 0m0,572s
buffer size: 262144 - 0m0,459s
buffer size: 524288 - 0m0,559s
buffer size: 1048576 - 0m0,618s

Syscalls:
buffer size: 1 - 0m8,326s
buffer size: 2 - 0m4,351s
buffer size: 4 - 0m2,439s
buffer size: 8 - 0m1,404s
buffer size: 16 - 0m0,854s
buffer size: 32 - 0m0,594s
buffer size: 64 - 0m1,590s
buffer size: 128 - 0m0,473s
buffer size: 256 - 0m0,449s
buffer size: 512 - 0m0,869s
buffer size: 1024 - 0m0,966s
buffer size: 2048 - 0m0,672s
buffer size: 4096 - 0m0,477s
buffer size: 8192 - 0m0,541s
buffer size: 16384 - 0m0,475s
buffer size: 32768 - 0m0,673s
buffer size: 65536 - 0m0,849s
buffer size: 131072 - 0m0,397s
buffer size: 262144 - 0m0,452s
buffer size: 524288 - 0m0,484s
buffer size: 1048576 - 0m0,610s
```

Transformado-os em um gráfico, fica da seguinte forma:  

![syscalls](syscalls.png)
![libc](libc.png)

## Conclusões
De acordo com os resultados, a conclusão foi que utilizar funções da **libc** é mais eficiente e mais rápida que funções do sistema (syscalls), por isso devemos utilizá-la ao invés de funções do sistema.
