GithubHelp home page GithubHelp logo

acerv / runltp-ng-original Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 3.0 237 KB

Next-gen LTP runner

License: GNU General Public License v2.0

Python 99.64% Makefile 0.36%
kernel linux-kernel testing-framework linux linux-test linux-test-project python

runltp-ng-original's Introduction

Runltp-ng

LTP Next-Gen runner is a new version of the runltp script used by the Linux Test Project.

Host information

    System: Linux
    Node: susy
    Kernel Release: 5.14.21-150400.24.33-default
    Kernel Version: #1 SMP PREEMPT_DYNAMIC Fri Nov 4 13:55:06 UTC 2022 (76cfe60)
    Machine Architecture: x86_64
    Processor: x86_64

    Temporary directory: /tmp/runltp.acer/tmpcwtket0m

Connecting to SUT: host
Downloading suite: math
Starting suite: math
abs01: pass | tained  (0.005s)
atof01: pass | tained  (0.005s)
float_bessel: pass | tained  (0.702s)
float_exp_log: pass | tained  (0.703s)
float_iperb: pass | tained  (0.288s)
float_power: pass | tained  (0.540s)
float_trigo: pass | tained  (0.643s)
fptest01: pass | tained  (0.020s)
fptest02: pass | tained  (0.005s)
nextafter01: pass | tained  (0.004s)

Suite Name: math
Total Run: 10
Elapsed Time: 2.9 seconds
Passed Tests: 22
Failed Tests: 0
Skipped Tests: 0
Broken Tests: 0
Warnings: 0
Kernel Version: Linux 5.14.21-150400.24.33-default #1 SMP PREEMPT_DYNAMIC Fri Nov 4 13:55:06 UTC 2022 (76cfe60)
CPU: x86_64
Machine Architecture: x86_64
RAM: 15569564 kB
Swap memory: 2095424 kB
Distro: opensuse-leap
Distro Version: 15.4


Disconnecting from SUT: host

Quickstart

Some basic commands are the following:

# run syscalls and dio testing suites on host
./runltp-ng --run-suite syscalls dio

# run syscalls and dio testing suites in qemu VM
./runltp-ng --sut qemu:image=folder/image.qcow2 \
    --run-suite syscalls dio

# run syscalls and dio testing suites via SSH
# NOTE: paramiko and scp packages must be installed in the system
./runltp-ng --sut=ssh:host myhost.com:user=root:key_file=myhost_id_rsa \
    --run-suite syscalls dio

It's possible to run a single command before running testing suites using --run-cmd option as following:

runltp-ng --run-cmd /mnt/testcases/kernel/systemcalls/bpf/bpf_prog02 \
    --sut qemu:image=folder/image.qcow2:virtfs=/home/user/ltp \
    --ltp-dir /mnt \
    --run-suite syscalls dio

It can be used also to run a single command without running testing suites:

runltp-ng --run-cmd /mnt/testcases/kernel/systemcalls/bpf/bpf_prog02 \
    --sut qemu:image=folder/image.qcow2

Every session has a temporary directory which can be found in /<TMPDIR>/runltp-of<username>. Inside this folder there's a symlink called latest, pointing to the latest session's temporary directory, and the application will rotate over 5 sessions.

For more information, checkout the following video at the SUSE Labs Conference 2022:

Watch the video

Setting up console for Qemu

To enable console on a tty device for a VM do:

  • open /etc/default/grub
  • add console=$tty_name, console=tty0 to GRUB_CMDLINE_LINUX
  • run grub-mkconfig -o /boot/grub/grub.cfg

Where $tty_name should be ttyS0, unless virtio serial type is used (i.e. if you set the serial=virtio backend option, then use hvc0)

Implementing SUT

Sometimes we need to cover complex testing scenarios, where the SUT uses particular protocols and infrastructures, in order to communicate with our host machine and to execute tests binaries.

For this reason, runltp-ng provides a plugin system to recognize custom SUT class implementations inside the ltp package folder. Please check host.py or ssh.py implementations for more details.

Once a new SUT class is implemented and placed inside the ltp package folder, runltp-ng -s help command can be used to see if application correctly recognise it.

Development

The application is validated using pytest and pylint. To run unittests:

pytest

To run linting checks:

pylint --rcfile=pylint.ini ./ltp

History

The LTP runltp code is hard to read, maintain and some of its parts are legacy features which are not supported anymore. But if we focus closer on the results, runltp has done its job for a while since 2001. Nowadays, with new automation systems, easily accesible virtualization and bigger computing power, runltp became more and more obsolete, since its main goal was to test Linux Kernel on target and specific distro(s). Let's take a look at the issues we have:

  • it's hard to maintain and it's based on a mixture of bash/C, both hard to read and not maintained anymore
  • it contains many features which are not used and they can be deprecated
  • report files are custom format logs or HTML files which are both hard to parse inside i.e. an automation system
  • if a test causes system crash, which is common for kernel tests, the tool crashes and we loose most or even all results we obtained before its execution. This means we need to run it inside a virtualized system to be sure that if system crashes, we won't loose control of the machine. And, in any case, we will loose testing report

The last point is really important, since in a world where cloud and embedded systems are having a big market, we need to provide a usable and a stable way to test Linux Kernel. Something that runltp is not able to achieve nowadays.

The new runltp-ng features

Cyril Hrubis started the first Perl prototype of runltp-ng (https://github.com/metan-ucw/runltp-ng/), a next generation tests runner that allows to run tests on a host, as well as inside a Qemu instance or over a SSH. The tool provided results in a machine parsable format which were easy to consume by automation systems. However as the community didn't like the choice of Perl programming language we decided to switch from Perl to Python to take advantage of the Python community size, easier maintenance and packages (https://github.com/acerv/runltp-ng).

In particular, we tried to focus on missing features and got rid of the ones which were not strictly needed. We ended up with a simple and light tool having the following features:

  • test suites can run inside a virtualized system using Qemu or they can be executed via SSH protocol
  • runner became more robust so it can gracefully handle kernel crashes and tained statuses of the kernel. At the moment, only Qemu supports this feature
  • report file type is JSON by default, so it will be easier to parse with external tools and automation systems
  • the user interface has been simplified, so we have two modes: quiet and verbose mode. The quiet mode is the default one and it shows only tests names and their results on a list. Verbose mode is similar to the current runltp stdout

What's next?

Nowadays runltp-ng is a simple and lightweight implementation that is based on Python 3.6+ and it doesn't have any dependency from external packages. Its skeleton is easy to understand and features can be added easily.

A missing feature that is currently under development is the possibility to execute tests via LTX (experimental).

LTX is a small service that runs on target and it permits to communicate via msgpack (https://msgpack.org/) in order to execute binaries on host in the fastest way as possible. Its development is currently maintained by Richard Palethorpe and we plan to make it the default LTP runner in the next future. When LTP metadata file will be completed, LTX will also permit to execute tests in parallel.

By taking in consideration previous topics, we can still provide an usable and simple tool that can replace current runltp script inside the LTP upstream. Its usage is simple, pretty stable and we are starting to move forward into a modern approach to schedule and run tests in the Linux Testing Project.

runltp-ng-original's People

Contributors

acerv avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

runltp-ng-original's Issues

Skip option to skip tests

A --skip-tests option might be useful to avoid running tests which should be ignored.
A --skip-file option might be useful to avoid running tests defined inside the skipfile.

Add test command line and duration to verbose output

Current output in 3dd3ae5:

# runltp-ng -r net.nfs -v
Host information

	System: Linux
	Node: debian-testing-btrfs
	Kernel Release: 5.19.0-2-amd64
	Kernel Version: #1 SMP PREEMPT_DYNAMIC Debian 5.19.11-1 (2022-09-24)
	Machine Architecture: x86_64
	Processor: 

	Temporary directory: /tmp/runltp.root/tmpd79zli5i

Connecting to SUT: host
Downloading suite: /opt/ltp/runtest/net.nfs
Starting suite: net.nfs
running nfs3_01
nfs01 1 TINFO: initialize 'lhost' 'ltp_ns_veth2' interface
nfs01 1 TINFO: add local addr 10.0.0.2/24
nfs01 1 TINFO: add local addr fd00:1:1:1::2/64
nfs01 1 TINFO: initialize 'rhost' 'ltp_ns_veth1' interface
nfs01 1 TINFO: add remote addr 10.0.0.1/24
nfs01 1 TINFO: add remote addr fd00:1:1:1::1/64
nfs01 1 TINFO: Network config (local -- remote):
nfs01 1 TINFO: ltp_ns_veth2 -- ltp_ns_veth1
nfs01 1 TINFO: 10.0.0.2/24 -- 10.0.0.1/24
nfs01 1 TINFO: fd00:1:1:1::2/64 -- fd00:1:1:1::1/64
nfs01 1 TINFO: ceiling LTP_TIMEOUT_MUL to 11
nfs01 1 TINFO: timeout per run is 0h 55m 0s
nfs01 1 TINFO: mount.nfs: (linux nfs-utils 1.3.3)
nfs01 1 TINFO: setup NFSv3, socket type udp
nfs01 1 TINFO: Mounting NFS: mount -v -t nfs -o proto=udp,vers=3 10.0.0.2:/tmp/LTP_nfs01.WiLlSnXh8w/3/udp /tmp/LTP_nfs01.WiLlSnXh8w/3/0
mount.nfs: trying 10.0.0.2 prog 100003 vers 3 prot UDP port 2049
mount.nfs: trying 10.0.0.2 prog 100005 vers 3 prot UDP port 47843
mount.nfs: mount(2): Invalid argument
mount.nfs: an incorrect mount option was specified
mount.nfs: timeout set for Wed Nov  2 15:22:28 2022
mount.nfs: trying text-based options 'proto=udp,vers=3,addr=10.0.0.2'
mount.nfs: prog 100003, trying vers=3, prot=17
mount.nfs: prog 100005, trying vers=3, prot=17
nfs01 1 TCONF: UDP support disabled with the kernel config NFS_DISABLE_UDP_SUPPORT?
TINFO: Cleaning up testcase

Summary:
passed   0
failed   0
broken   0
skipped  1
warnings 0
running nfs3t_01

It'd be great to have 1) command line 2) verbose output 3) separate each test somehow, .e.g.:

Starting suite: net.nfs
* running nfs3_01
cmd: nfs01.sh -v 3 -t udp
nfs01 1 TINFO: initialize 'lhost' 'ltp_ns_veth2' interface
nfs01 1 TINFO: add local addr 10.0.0.2/24
nfs01 1 TINFO: add local addr fd00:1:1:1::2/64
...

Summary:
passed   0
failed   0
broken   0
skipped  1
warnings 0

duration: 20s

* running nfs3t_01

LTP python-runner tests in Publiccloud return SUTError

A progress.opensuse.org issues has been created, check poo# 119812.

After prepared the LTP test python runner as in poo#116668, the scheduled runltp-python tests in public cloud-Development group 447 started, but some tests initially failed all for the same issue and were restarted 3 times before to pass, so 2 tests failed and last one passed, in 2 different builds.

In particular the first runs of kernel-ec2:
syscalls: https://openqa.suse.de/tests/9856819#step/run_ltp/50
cve: https://openqa.suse.de/tests/9856226#step/run_ltp/50
failed both with the same error:

# wait_serial expected: qr/wKYTI-\d+-/u
# Result:

Host information

    System: Linux
    Node: install
    Kernel Release: 5.3.18-150300.59.98-default
    Kernel Version: #1 SMP Thu Oct 13 08:52:00 UTC 2022 (dfcde7e)
    Machine Architecture: x86_64
    Processor: x86_64

    Temporary directory: /tmp/runltp.root/tmpkhgmmrz6

Connecting to SUT: ssh
Error: Can't read return code from reply '\n'

Traceback (most recent call last):
  File "runltp-ng/ltp/session.py", line 278, in run_single
    sut_config)
  File "runltp-ng/ltp/session.py", line 172, in _start_sut
    iobuffer=Printer(sut, False))
  File "runltp-ng/ltp/ssh.py", line 309, in communicate
    iobuffer=iobuffer)
  File "runltp-ng/ltp/ssh.py", line 465, in run_command
    f"Can't read return code from reply {repr(reply)}")
ltp.sut.SUTError: Can't read return code from reply '\n'

wKYTI-1-

That same error was already noted in the past and initially, it was resolved with a patch in the ssh module, adding a sleep time, but it re-occurred now and is not deterministic, test reruns sometime pass: probably related to some sync timing.

Please check more details in the above named poo# 119812.

Support old skip-tests syntax

We are currently skipping tests using a simple list of names, but instead we would like to use regexp as the old Perl version.

For example:
'creat09|ptrace10|_16\$|^(move_pages|msg(ctl|get|rcv|snd|stress)|sem(ctl|get|op|snd)|shm(at|ctl|dt|get)|syslog|inotify07|inotify08|epoll_wait0[2-3]|getrusage04|writev03)|init_module0[1-2]|finit_module0[1-2]|delete_module01|delete_module03|setsockopt08|^(preadv203_64|preadv203|delete_module01|inotify08|delete_module03|finit_module01|init_module01|init_module02|inotify07|finit_module02)\$

Write test command line to dmesg

It'd be handy to write before testing to dmesg test command line, e.g.:

[119926.032365] runltp-ng: nfs01.sh -v 3 -t udp # nfs3_01

That's handy to see which test caused kernel oops:

[   56.421235] runltp-ng: nfs01.sh -v 3 -t udp # nfs3_01
[   56.425297] IPv6: ADDRCONF(NETDEV_CHANGE): ltp_ns_veth2: link becomes ready
[   56.994220] ------------[ cut here ]------------
[   56.995752] memcpy: detected field-spanning write (size 28) of single field "&ctx->nfs_server.address" at fs/nfs/namespace.c:178 (size 16)
[   56.999329] WARNING: CPU: 0 PID: 3456 at fs/nfs/namespace.c:178 nfs_d_automount+0x24c/0x290 [nfs]
[   57.001642] Modules linked in: rpcsec_gss_krb5(E) nfsv4(E) dns_resolver(E) nfsv3(E) nfs(E) fscache(E) netfs(E) xfrm_user(E) xfrm_algo(E) veth(E) qrtr(E) af_packet(E) rfkill(E) intel_rapl_msr(E) intel_rapl_common(E) intel_pmc_core_pltdrv(E) intel_pmc_core(E) snd_hda_codec_generic(E) ledtrig_audio(E) kvm_intel(E) iTCO_wdt(E) intel_pmc_bxt(E) iTCO_vendor_support(E) snd_hda_intel(E) snd_intel_dspcfg(E) snd_intel_sdw_acpi(E) snd_hda_codec(E) snd_hda_core(E) snd_hwdep(E) kvm(E) snd_pcm(E) irqbypass(E) pcspkr(E) snd_timer(E) lpc_ich(E) i2c_i801(E) snd(E) i2c_smbus(E) virtio_net(E) soundcore(E) net_failover(E) joydev(E) virtio_balloon(E) failover(E) tiny_power_button(E) button(E) nfsd(E) auth_rpcgss(E) nfs_acl(E) lockd(E) grace(E) sunrpc(E) fuse(E) configfs(E) ip_tables(E) x_tables(E) hid_generic(E) usbhid(E) crct10dif_pclmul(E) crc32_pclmul(E) polyval_clmulni(E) polyval_generic(E) gf128mul(E) ghash_clmulni_intel(E) sha512_ssse3(E) xhci_pci(E) xhci_pci_renesas(E) aesni_intel(E)
[   57.001720]  crypto_simd(E) cryptd(E) xhci_hcd(E) serio_raw(E) virtio_rng(E) virtio_blk(E) virtio_gpu(E) virtio_dma_buf(E) usbcore(E) btrfs(E) blake2b_generic(E) libcrc32c(E) crc32c_intel(E) xor(E) raid6_pq(E) sg(E) dm_multipath(E) dm_mod(E) scsi_dh_rdac(E) scsi_dh_emc(E) scsi_dh_alua(E) qemu_fw_cfg(E)
[   57.023194] Unloaded tainted modules: intel_tcc_cooling(E):2 pcc_cpufreq(E):2 acpi_cpufreq(E):2
[   57.032411] CPU: 0 PID: 3456 Comm: mount.nfs Tainted: G        W   E      6.1.0-rc3-0.g3b74e67-default #1 openSUSE Tumbleweed (unreleased) 83d9036cc26826a41b4e9f7bea95f22c34b218fc
[   57.036793] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.0-0-gd239552-rebuilt.opensuse.org 04/01/2014
[   57.040207] RIP: 0010:nfs_d_automount+0x24c/0x290 [nfs]
[   57.041962] Code: 10 00 00 00 4c 89 ee 4c 89 04 24 48 c7 c2 48 02 d4 c0 48 c7 c7 88 02 d4 c0 48 89 44 24 08 c6 05 8c d3 03 00 01 e8 66 7a 3d e1 <0f> 0b 48 8b 44 24 08 4c 8b 04 24 e9 b7 fe ff ff be 01 00 00 00 e8
[   57.046884] RSP: 0000:ffffa328c1fcf9d0 EFLAGS: 00010286

Fix test output in single line on -c

Running ping01.sh directly EOL is ok:

# PATH="/opt/ltp/testcases/bin:$PATH" ping01.sh
ping01 1 TINFO: initialize 'lhost' 'ltp_ns_veth2' interface
ping01 1 TINFO: add local addr 10.0.0.2/24
ping01 1 TINFO: add local addr fd00:1:1:1::2/64
ping01 1 TINFO: initialize 'rhost' 'ltp_ns_veth1' interface
ping01 1 TINFO: add remote addr 10.0.0.1/24
ping01 1 TINFO: add remote addr fd00:1:1:1::1/64
ping01 1 TINFO: Network config (local -- remote):
ping01 1 TINFO: ltp_ns_veth2 -- ltp_ns_veth1
ping01 1 TINFO: 10.0.0.2/24 -- 10.0.0.1/24
ping01 1 TINFO: fd00:1:1:1::2/64 -- fd00:1:1:1::1/64
ping01 1 TINFO: timeout per run is 0h 5m 0s
ping01 1 TINFO: ping with 8 16 32 64 128 256 512 1024 2048 4064 ICMP packets
ping01 1 TPASS: ping -i 0.2 -c 3 -s 8 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 16 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 32 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 64 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 128 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 256 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 512 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 1024 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 2048 10.0.0.1 >/dev/null passed as expected
ping01 1 TPASS: ping -i 0.2 -c 3 -s 4064 10.0.0.1 >/dev/null passed as expected

Summary:
passed   10
failed   0
broken   0
skipped  0
warnings 0

But running with runltp-ng there is no new line:

# runltp-ng -v -c ping01.sh
Host information

	System: Linux
	Node: debian-testing-btrfs
	Kernel Release: 5.19.0-2-amd64
	Kernel Version: #1 SMP PREEMPT_DYNAMIC Debian 5.19.11-1 (2022-09-24)
	Machine Architecture: x86_64
	Processor: 

	Temporary directory: /tmp/runltp.root/tmp33r265eg

Connecting to SUT: host
ping01.sh
ping01 1 TINFO: initialize 'lhost' 'ltp_ns_veth2' interfaceping01 1 TINFO: add local addr 10.0.0.2/24ping01 1 TINFO: add local addr fd00:1:1:1::2/64ping01 1 TINFO: initialize 'rhost' 'ltp_ns_veth1' interfaceping01 1 TINFO: add remote addr 10.0.0.1/24ping01 1 TINFO: add remote addr fd00:1:1:1::1/64ping01 1 TINFO: Network config (local -- remote):ping01 1 TINFO: ltp_ns_veth2 -- ltp_ns_veth1ping01 1 TINFO: 10.0.0.2/24 -- 10.0.0.1/24TINFO: fd00:1:1:1::2/64 -- fd00:1:1:1::1/64ping01 1 TINFO: ceiling LTP_TIMEOUT_MUL to 11ping01 1 TINFO: timeout per run is 0h 55m 0sping01 1 TINFO: ping with 8 16 32 64 128 256 512 1024 2048 4064 ICMP packetsping01 1 TPASS: ping -i 0.2 -c 3 -s 8 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 16 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 32 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 64 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 128 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 256 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 512 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 1024 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 2048 10.0.0.1 >/dev/null passed as expectedping01 1 TPASS: ping -i 0.2 -c 3 -s 4064 10.0.0.1 >/dev/null passed as expectedSummary:passed   10failed   0broken   0skipped  0warnings 0
Exit code: 0

Disconnecting from SUT: host

Tested on current master: 3dd3ae5.

More info in test output (duration, test command line)

I'd prefer to have a bit more in test output. E.g. instead of:

# runltp-ng -r net.nfs
...
Starting suite: net.nfs
nfs3_01: skip | tained
nfs3t_01: pass | tained
...

have test duration (printed user friendly - results.json contains non-user friendly: e.g. 0.20882654190063477):

nfs3_01: skip | tained (20s)
nfs3t_01: pass | tained (1min 30s)

or test duration and test command line:

nfs3_01: skip | tained duration: 20s, cmd: nfs01.sh -v 3 -t udp
nfs3t_01: pass | tained duration: 1min 30s, cmd: nfs01.sh -v 3 -t tcp

Although some tests have quite long cmdline, thus maybe have it on separate line. e.g: net_stress.ipsec_icmp:

icmp6-uni-basic08 icmp-uni-basic.sh -6 -A rfc4106_128 -p esp_aead -m transport -s 10:100:1000:10000:65490

thus ok, if you add it just to verbose mode (https://github.com/acerv/runltp-ng/issues/18).

Remove colors rules

At the moment we have 3 types of colors rules, but it would be nice to keep only 2: none and LTP tests default colors. To do so, we need to parse the tests stdout and to remove all colors characters which are added inside stdout text.

Add initrd/kernel support in qemu

It would be interesting to add a feature to handle -kernel and -initrd options inside qemu SUT implementation.
This is particularly useful when building kernel using buildroot that generates two different files: kernel and rootfs.

Dynamically load SUT implementation

It would be nice to dynamically load SUT implementation so it's easier to include custom SUT communication without introducing new runltp-ng modifications.

cleanup option

To add a --cleanup option to avoid storing information in the /tmp/runltp-of-<user> folder, if needed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.