Først noen praktiske oppgaver om plattformavhengighet, deretter noen praktiske og teoretiske oppgaver om tråder, så et
par Docker compose oppgaver og til slutt som vanlig en konkurranse-oppgave.
Det er ikke flere obligatoriske innleveringer, så betrakt oppgaver som er
merket (Oblig) som de oppgavene det er viktigst å få med seg i forbredelsene til eksamen.
- (Oblig)
Ta utgangspunkt i følgende C-program:
#include <stdio.h>
main()
{
printf("c: Hello world!\n");
}
Skriv dette inn i en fil hello.c på data2500 eller os-VM ved å starte f. eks. editoren jed:
$ jed hello.c
lagre filen og kompiler den med
$ gcc hello.c
gcc er C-kompilatoren. For å kunne kompilere og kjøre C-programmet, må gcc være installert, slik den er på data2500 og os-VM. Den lager nå maskinkode som lagres i
den kjørbare filen a.out. For å få lov til å kjøre den, må filen gis kjørerettigheter og
det gjør du med kommandoen
$ chmod 700 a.out
Kjør programmet med
$ a.out
og du bør nå få ut "Hello world" i terminalvinduet.
- a) Kan du se på den kjørbare filen og finne ut noe om hvilket operativsystem koden er kompilert for?
Logg så inn på en Windows maskin (eventuelt på en Mac og gjør det tilsvarende som beskrevet for Windows).
Kopier a.out med Winscp eller på annen måte, og kjør det fra der du har lagt
det med
C:\>a.out
- b) Forklar hva som skjer.
- c) Hvordan kan du få til å kjøre hello.c på Windows (eventuelt på Mac)?
-
Ta utgangspunkt i følgende Java-program
class Hello
{
public static void main(String args[])
{
System.out.println("Java: Hello world!");
}
}
og lagre det i filen Hello.java på Linux-VM eller data2500. Java er installert her, på andre servere kan man installere java og java-kompilatoren javac med
apt-get install default-jdk
På Linux kompileres et Java-program med
$ javac Hello.java
det lages da byte-kode som lagres i en fil Hello.class som kjøres med
$ java Hello
og sjekk at den kjører som den skal.
Kopier over Hello.class til en Windows-PC. Får du den til å kjøre her?
Vil det i prinsippet være mulig?
-
Hvilke av følgende programmeringsspråk kan betegnes som plattformuavhengige? C, C++, Java og Python. Forklar svaret kort.
- (Oblig)
Kopier Java-programmet Calc.java fra avsnitt 10.9 i forelesningen til Linux-VM
og lagre det med samme navn.
Kompiler så med
javac Calc.java
og sjekk at det lages en Calc.class fil. Kjør programmet med
java Calc
Om det går for fort, gang verdien på telleren i programmet med 10 eller mer, kompiler og kjør igjen.
- a)
Tving java til å kjøre på bare en CPU med taskset. Hvor mye CPU får hver tråd?
Endre koden slik at det starter tre tråder istedet for to og tving igjen alle til å kjøre på samme CPU med taskset.
Tast H i top hvis tråder ikke vises.
- b)
Hvor mye CPU-tid får hver tråd i snitt når det kjører?
- c)
Hvor mange java-tråder kjøres totalt når du starter dette Java-programmet?
Hint: Se på nTH = Number of Threads i top eller bruk ps -L. Hvis man taster 'u' i top og så skriver inn sitt brukernavn (f.eks. group100) vil man kun se denne brukerens prosesser/tråder. En annen mulighet er å installere htop som viser tråder.
- (Oblig)
Studer og kjør følgende kode på din Linux-VM:
import java.lang.Thread; import java.io.PrintStream;
class CalcThread extends Thread { static int count = 0; int id; long res=0; CalcThread() { count++; id = count; }
public void run() { System.out.println("Thread nr." + id + " is starting"); res = work(); }
private long work() { long i,j; if(id == 1) { System.out.println("Thread nr." + id + " calculating"); for(i = 1;i <= 4000000000L;i++) { res += i; } } return(res); } }
class Calc { public static void main(String args[]) { System.out.println("Starts two threads!"); CalcThread s1 = new CalcThread(); System.out.println("Thread s1 has id " + s1.id); s1.start(); // Allokerer minne og kaller s.run() CalcThread s2 = new CalcThread(); System.out.println("Thread s2 has id " + s2.id); s2.start(); System.out.println("s2 started !\n"); try { s1.join(); } catch (InterruptedException e) { } try { s2.join(); } catch (InterruptedException e) { } System.out.printf("Thread nr. 1 calculated %d\n",s1.res); System.out.printf("Thread nr. 2 calculated %d\n",s2.res); } }
|
Resultatet av denne kjøringen er et veldig stort heltall, derfor heter variablene long istedet for int, long er 64 bit lange, mens int er 32 bit. Det er også årsaken til at tallet 4 milliarder i work-løkken slutter med en L, den må med når så lange siffer skal skrives inn i koden. Den ene tråden i koden regner ut summen av alle tall mellom 1 og 4 milliarder, mens den andre tråden ikke gjør noe. Kallene s1.join og s2.join inne i main gjør at main venter til begge trådene er ferdige med sine beregninger før den avslutter.
Ta tiden på hvor lang tid beregningen tar. Klarer du å få programmet til å regne ut samme sluttresultat dobbelt så fort ved å fordele beregningene på begge trådene og utnytte to CPUer samtidig?
-
I 2020 når Linux-VM-ene virkelig var virtuelle maskiner, hadde vi følgende oppgave:
Hvis du har problemer med diskplass på Linux VM'en, kan du forsøke å slette noen filer og starte med følgende:
- df viser hvor mye diskplass du har
- Kjør apt-get clean
- Kjør som root du -sm /* som viser bruk per mappe i MByte. Spesifiser så f. eks. /var/*
- Slett filer som er store og overflødige.
- /usr/share/doc/* er 100M som kan fjernes
- /var/log/btmp* kan slettes. Er gjerne stor, ssh innlogging
- Følgende viser installasjonene som tar størst plass: # dpkg-query -W --showformat='${Installed-Size} ${Package}\n' | sort -n
Hvorfor er ikke denne oppgaven like relevant i år? Hvilke deler av den er fortsatt relevant?
-
(Oppgave 2.8 i Tanenbaum). I en tabell i boken blir registere listet som en "Per thread item" sammen med Program Counter og stack,
og ikke som en "Per process item" sammen med globale variabler, åpne filer og child prosesser.
Hvorfor? En maskin har jo bare ett sett med registere?
-
Oppgave 2.9 i Tanenbaum: Hvorfor vil en tråd noengang frivillig gi fra seg CPU'en
ved å kalle yield()? Siden det ikke finnes noe periodisk klokke-interupt innenfor en prosess,
kan det jo være at den aldri får igjen CPU'en.
-
Oppgave 2.10 i Tanenbaum: Kan en tråd bli preempted(tvunget til å stoppe å kjøre) av et
klokke-interrupt? Isåfall, under hvilke omstendigheter? Hvis ikke, hvorfor ikke?
-
Problem 2.18 i Tanenbaum. I et system med threads, er det en stack per thread eller en stack per prosess når
user-level threads blir brukt? Hva når kernel-level threads blir brukt? Forklar.
-
Lag en docker-compose.yaml fil som starter opp to nginx-containere som begge er bygget fra den samme Dockerfile som ligger i en mappe du kan kalle nginx. Når de starter opp skal de to containerne som kjører nginx-webserveren på henholdsvis port 8080 og 8081 gi data fra to forskjellige index.html filer fra mapper på host'en som containerene kjører på. Omtrent slik som i eksempelet fra forelesningsnotatene.
Dockerfile skal sørge for at både iputils-ping og net-tools er installert når de to containerene starter opp. Vis så at du kan gå inn på en av containerene og pinge den andre. Hvis også ved hjelp av kommandoen ifconfig inne i containerene hvilke IP-adresser de har fått på det lokale nettverket. Er selve host'en som kjører docker også på dette nettverket?
- (Oblig)
Lag på Linux-VM en docker-compose.yaml fil som starter opp to nginx-containere web1 og web2 som begge kjører nginx-webserver på port 80 og som gir to små men forskjellige index.html filer fra mapper på host'en som containerene kjører på. Innholdet kan være navnet på webserveren, slik at man kan se forskjell. Neste steg er å legge til en container som kan kalles loadbalancer i docker-compose.yaml. Lag først en mappe nginx som inneholder følgende fil med navn default.conf:
upstream backend {
random;
server web1;
server web2;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
Dette er en config fil som gjør nginx om til en load balancer og dermed blir en container som fordeler web-forespørsler på port 80 som kommer inn til Linux-VMen likt mellom de to webeserverene web1 og web2. Lag i nginx-mappen en Dockerfile som laster inn nginx og så kopierer filen default.conf til /etc/nginx/conf.d/default.conf på loadbalancer-containeren. Legg så til kode i docker-compose.yaml som gjør at loadbalancer bygges slik at den tar imot trafikk inn til Linux-VM inn på sin port 80. Bygg så hele systemet med
root@os131:~/load# docker compose up --build -d
og sjekk at loadbalancer virker som den skal. Opsjonen --build gjør at det alltid bygges på nytt fra Dockerfile om det har blitt gjort noen endringer. Når alt er satt opp slik det skal, kan det utenifra se ut som følger:
haugerud@data2500:~$ for i in {1..10}; do curl os131.vlab.cs.oslomet.no; done
web2
web1
web2
web2
web2
web1
web1
web2
web1
web1
hvor vi ser at web-serverene bytter på å svare (om man ikke tar med 'random' i nginx-konfigurasjonen tar det litt tid før den begynner å bytte på). Og på Linux-VM kan det se omtrent slik ut:
root@os131:~/load# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
090e8fb7be56 nginx:latest "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 80/tcp load_web2_1
ebcee4527e57 nginx:latest "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 80/tcp load_web1_1
b3dd3867c9bf load_loadbalancer "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 0.0.0.0:80->80/tcp load_loadbalancer_1
root@os131:~/load#
- (Oblig)
Dette er ukens konkurranse-oppgave som egentlig løses på en hvilken som helst server som kjører docker
og for eksempel på s-serveren eller på os-serveren. Du skal laste ned fra repositoriet haugerud/os25 på
Dockerhub
en versjon av os-containeren som har samme tag/versjonsnummer som din s-gruppe. For eksempel versjonsnummer s68 om du har
s-nummer 68 på s-serveren. NB! Pass på at du bruker ditt eget s-nummer (og ikke os-nummer), ellers vil du løse oppgaven for en annen!
Se mer om hvordan man laster ned containere i avsnitt 9.2 Dockerhub i forelesningsnotatene.
Deretter skal du starte denne containeren som er en nginx webserver. Det er en vanlig web-server, men den er spesiell på den
måten at man må koble seg til på port 12345 for å se innholdet, og ikke port 80 som
er standard for webservere. Når du kobler deg til denne webserveren vil det eneste
innholdet på denne være en 10-tegns kode med tilfeldige tegn som viser at du har løst oppgaven.
For å sjekke at du har funnet det rette ordet, skriv strengen med 10 tegn inn på siden
os.php uke 13
og du får beskjed om du har skrevet riktig. I tilegg blir du da med på OS-konkurransen om å finne denne koden fortest mulig!