Adhika Setya Pramudita

Adhika Setya Pramudita

Collection of thoughts

16 Feb 2025

Ping Test to Popular Websites

First, we define the webiste to ping. This is collection of popular websites + some Indonesian websites.
Show code (37 lines)
 1websites = [
 2    'google.com',
 3    'facebook.com', 
 4    'apple.com',
 5    'amazon.com',
 6    'microsoft.com',
 7    'netflix.com',
 8    'twitter.com',
 9    'instagram.com',
10    'linkedin.com',
11    'youtube.com',
12    'reddit.com',
13    'wikipedia.org',
14    'github.com',
15    'yahoo.com',
16    'twitch.tv',
17    'tiktok.com',
18    'spotify.com',
19    'whatsapp.com',
20    'zoom.us',
21    'discord.com',
22    'pinterest.com',
23    'dropbox.com',
24    'salesforce.com',
25    'tokopedia.com',
26    'shopee.co.id',
27    'zalora.co.id',
28    'lazada.co.id',
29    'bukalapak.com',
30    'blibli.com',
31    'kompas.com',
32    'detik.com',
33    'tribunnews.com',
34    'cnbcindonesia.com',
35    'okezone.com',
36    'liputan6.com',
37]
We then define the function to ping the website. Will use the ping command.
Show code (42 lines)
 1import subprocess
 2
 3def ping_website(website):
 4    try:
 5        result = subprocess.run(['ping', '-c', '10', website], 
 6                              capture_output=True, 
 7                              text=True,
 8                              timeout=10)
 9        
10        if result.returncode == 0:
11            # Get IP address from first line
12            first_line = result.stdout.split('\n')[0]
13            ip_address = first_line.split('(')[1].split(')')[0]
14            
15            # Get all ping times
16            ping_times = []
17            for line in result.stdout.split('\n')[1:-5]: # Skip first and last summary lines
18                if 'bytes from' in line:
19                    time = float(line.split('time=')[1].split()[0])
20                    ping_times.append(time)
21                    
22            status = 'Success'
23        else:
24            ip_address = None
25            ping_times = []
26            status = 'Failed'
27            
28    except subprocess.TimeoutExpired:
29        ip_address = None
30        ping_times = []
31        status = 'Timeout'
32    except Exception as e:
33        ip_address = None
34        ping_times = []
35        status = f'Error: {str(e)}'
36        
37    return {
38        'website': website,
39        'ip_address': ip_address,
40        'status': status,
41        'ping_times_ms': ping_times
42    }
Then we ping all websites. Do it in parallel so it don’t take much time.
 1import pandas as pd
 2import concurrent.futures
 3
 4results = []
 5with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
 6    future_to_website = {executor.submit(ping_website, website): website for website in websites}
 7    for future in concurrent.futures.as_completed(future_to_website):
 8        result = future.result()
 9        results.append(result)
10
11df = pd.DataFrame(results)

There are some websites that failed to ping. It is probably because the website is blocking ICMP ping requests as a security measure.

We can see this in the data where some entries have status=‘Failed’ or status=‘Timeout’

1df[df['status'] != 'Success'][['website', 'status']]
websitestatus
7apple.comTimeout
8linkedin.comTimeout
9netflix.comTimeout
29tokopedia.comTimeout
34detik.comTimeout
Now we calculate the statistics for the successful pings so we can glance some insights.
1# Calculate statistics for successful pings only
2df_stats = df[df['status'] == 'Success'].copy()
3df_stats['min_ms'] = df_stats['ping_times_ms'].apply(lambda x: min(x))
4df_stats['max_ms'] = df_stats['ping_times_ms'].apply(lambda x: max(x))
5df_stats['avg_ms'] = df_stats['ping_times_ms'].apply(lambda x: sum(x)/len(x))
6df_stats['p50_ms'] = df_stats['ping_times_ms'].apply(lambda x: sorted(x)[len(x)//2])
7df_stats['std_ms'] = df_stats['ping_times_ms'].apply(lambda x: pd.Series(x).std())
And chart the results.
 1import altair as alt
 2chart = alt.Chart(df_stats).mark_bar().encode(
 3    y=alt.Y('website:N', sort='x'),
 4    x=alt.X('avg_ms:Q', title='Average Ping Time (ms)'),
 5    tooltip=['website', 'avg_ms', 'min_ms', 'max_ms']
 6).properties(
 7    width=800,
 8    height=400,
 9    title='Average Ping Time by Website - lower is better'
10)
11chart

It is interesting to see that the ping latency of various websites fall under 3 ranges.

  1. Under 1-3 ms
  2. 10-15 ms
  3. 180++ ms

I am not sure why the case. There is no pattern that I can see. Whether it is international vs Indonesian websites, or the type of websites (news, e-commerce, etc).


🗒️ Download (notebook.ipynb)