I've learned. I'll share.

January 14, 2009

Popcount in Python (with benchmarks)

Purpose

A slightly uncommon bit-twiddling operation is "popcount", which counts the number high bits. While uncommon, it's crucial for implementing Array Mapped Tries, which is a way to implement immutable maps and vectors. I'm trying to implement immutable maps and vectors, so I needed to implement popcount.

I found A TON of ways, but had no idea which was fastest. So, I implemented them all and tested them. The short answer is to do this:

#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
POPCOUNT_TABLE16 = [0] * 2**16
for index in xrange(len(POPCOUNT_TABLE16)):
    POPCOUNT_TABLE16[index] = (index & 1) + POPCOUNT_TABLE16[index >> 1]

def popcount32_table16(v):
    return (POPCOUNT_TABLE16[ v        & 0xffff] +
            POPCOUNT_TABLE16[(v >> 16) & 0xffff])
And here's the long answer:

Results

I ran popcount on 30,000 random ints between 0 and 231-1. Here are the results from my Linux Desktop with a 3.2Ghz Core 2 Quad:

Name TimeMax BitsURL
c_bagwell 0.003032http://lamp.epfl.ch/papers/idealhashtrees.pdf
c_bsdmacro 0.003032http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
c_parallel 0.003132http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
c_ops64 0.003632http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
table16 0.009832http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
c_table8 0.011032http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
table+kern 0.0132 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
table8 0.016332http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
bsdmacro 0.019032http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
parallel 0.019932http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
ops64 0.020732http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
bagwell 0.024232http://lamp.epfl.ch/papers/idealhashtrees.pdf
freebsd 0.025732http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
timpeters3 0.027732http://mail.python.org/pipermail/python-list/1999-July/007696.html
timpeters2 0.058032http://mail.python.org/pipermail/python-list/1999-July/007696.html
timpeters 0.0724 ?http://mail.python.org/pipermail/python-list/1999-July/007696.html
kernighan 0.0745 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
elklund 0.0889 -http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
naive 0.1519 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
seistrup 0.2447 ?http://mail.python.org/pipermail/python-list/1999-July/007696.html

And here are the results for my MacBook with a 2.0Ghz Core 2 Duo:

Name TimeMax BitsURL
table16 0.027932http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
table+kern 0.0372 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
table8 0.041732http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
bsdmacro 0.048132http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
bagwell 0.059632http://lamp.epfl.ch/papers/idealhashtrees.pdf
timpeters3 0.074432http://mail.python.org/pipermail/python-list/1999-July/007696.html
parallel 0.080732http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
ops64 0.129032http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
timpeters2 0.143932http://mail.python.org/pipermail/python-list/1999-July/007696.html
kernighan 0.1527 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
timpeters 0.1668 ?http://mail.python.org/pipermail/python-list/1999-July/007696.html
freebsd 0.1772 -http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
elklund 0.1913 -http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
naive 0.2889 -http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
seistrup 0.6106 ?http://mail.python.org/pipermail/python-list/1999-July/007696.html

Observations

  1. Implementations written in C (using Pyrex) are 5-6 times faster than Python.
  2. My 3.2 Ghz Linux Desktop is 200% faster than my 2.0 Ghz MacBook even though it only has a 60% clockspeed advantage. I'm not sure what to make of that. Python doesn't use multiple cores well, so I'm sure it's not that.
  3. If you want to run popcount on 32-bit values in pure Python, table16 is the fastest by far, and only 3 times slower than implementations in C.
  4. If you need to run popcount on arbitrarily large integers, kernighan is the best, but doing a hybrid of table16 and kernighan is probably better.

Conclusion

If you don't mind using about 64KB of memory, here's is the fastest popcount in pure python:
#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
POPCOUNT_TABLE16 = [0] * 2**16
for index in xrange(len(POPCOUNT_TABLE16)):
    POPCOUNT_TABLE16[index] = (index & 1) + POPCOUNT_TABLE16[index >> 1]

def popcount32_table16(v):
    return (POPCOUNT_TABLE16[ v        & 0xffff] +
            POPCOUNT_TABLE16[(v >> 16) & 0xffff])
If you do mind the memory usage, here's a slighly slower version:
#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
POPCOUNT_TABLE8 = [0] * 2**8
for index in xrange(len(POPCOUNT_TABLE8)):
    POPCOUNT_TABLE8[index] = (index & 1) + POPCOUNT_TABLE8[index >> 1]

def popcount32_table8(v):
    return (POPCOUNT_TABLE8[ v        & 0xff] +
            POPCOUNT_TABLE8[(v >> 8)  & 0xff] +
            POPCOUNT_TABLE8[(v >> 16) & 0xff] +
            POPCOUNT_TABLE8[ v >> 24        ])
And if you need to handle values of more than 32 bits, one of these two are the best:
#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
def popcount_kernighan(v):
    c = 0
    while v:
        v &= v - 1
        c += 1
    return c

POPCOUNT32_LIMIT = 2**32-1
POPCOUNT_TABLE8 = [0] * 2**8
for index in xrange(len(POPCOUNT_TABLE8)):
    POPCOUNT_TABLE8[index] = (index & 1) + POPCOUNT_TABLE8[index >> 1]

def popcount_hybrid(v):
    if v <= POPCOUNT32_LIMIT:
        return (POPCOUNT_TABLE16[ v        & 0xffff] +
                POPCOUNT_TABLE16[(v >> 16) & 0xffff])
    else:
        c = 0
        while v:
            v &= v - 1
            c += 1
        return c

If it needs to be faster than that, write in C!

Test For Yourself

If you want to test these yourself, here's some code you can run.
#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
def popcount_naive(v):
    c = 0
    while v:
        c += (v & 1)
        v >>= 1
    return c

#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
def popcount_kernighan(v):
    c = 0
    while v:
        v &= v - 1
        c += 1
    return c

#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
POPCOUNT_TABLE8 = [0] * 2**8
for index in xrange(len(POPCOUNT_TABLE8)):
    POPCOUNT_TABLE8[index] = (index & 1) + POPCOUNT_TABLE8[index >> 1]

def popcount32_table8(v):
    return (POPCOUNT_TABLE8[ v        & 0xff] +
            POPCOUNT_TABLE8[(v >> 8)  & 0xff] +
            POPCOUNT_TABLE8[(v >> 16) & 0xff] +
            POPCOUNT_TABLE8[ v >> 24        ])

POPCOUNT_TABLE16 = [0] * 2**16
for index in xrange(len(POPCOUNT_TABLE16)):
    POPCOUNT_TABLE16[index] = (index & 1) + POPCOUNT_TABLE16[index >> 1]

def popcount32_table16(v):
    return (POPCOUNT_TABLE16[ v        & 0xffff] +
            POPCOUNT_TABLE16[(v >> 16) & 0xffff])

POPCOUNT32_LIMIT = 2**32-1
def popcount_table16_kernighan(v):
    if v <= POPCOUNT32_LIMIT:
        return (POPCOUNT_TABLE16[ v        & 0xffff] +
                POPCOUNT_TABLE16[(v >> 16) & 0xffff])
    else:
        c = 0
        while v:
            v &= v - 1
            c += 1
        return c


#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
def popcount32_ops64(v):
    return ((((v & 0xfff) * 0x1001001001001 & 0x84210842108421)            % 0x1f) +
            ((((v & 0xfff000) >> 12) * 0x1001001001001 & 0x84210842108421) % 0x1f) +
            (((v >> 24) * 0x1001001001001 & 0x84210842108421)              % 0x1f))
   

#http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
#also http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
def popcount32_parallel(v):
    v = v                - ((v >> 1) & 0x55555555)
    v = (v & 0x33333333) + ((v >> 2) & 0x33333333)
    #v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F)
    #v = v                + ((v >> 4) & 0x0F0F0F0F)
    v = (v + (v >> 4)) & 0x0F0F0F0F
    v = (v * 0x1010101) >> 24
    return v % 256 #I added %256. I'm not sure why it's needed. It's probably because of signed ints in Python

def popcount32_bagwell(v):
    v = v                - ((v >> 1) & 0x55555555)
    v = (v & 0x33333333) + ((v >> 2) & 0x33333333)
    v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F)
    v = v                +  (v >> 8)
    v = (v + (v >> 16)) & 0x3F
    return v

#http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
def popcount_elklund(v):
    c = 0
    while v:
        v ^= v & -v
        c += 1
    return c

#http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
def popcount32_freebsd(v):
    v = (v & 0x55555555) + ((v & 0xaaaaaaaa) >> 1);
    v = (v & 0x33333333) + ((v & 0xcccccccc) >> 2);
    v = (v & 0x0f0f0f0f) + ((v & 0xf0f0f0f0) >> 4);
    v = (v & 0x00ff00ff) + ((v & 0xff00ff00) >> 8);
    v = (v & 0x0000ffff) + ((v & 0xffff0000) >> 16);
    return v

#http://resnet.uoregon.edu/~gurney_j/jmpc/bitwise.html
def popcount32_bsdmacro(v):
    #define BITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255)
    #define BX_(x) ((x) - (((x)>>1)&) - (((x)>>2)&0x33333333) - (((x)>>3)&0x11111111))
    #
    #def bx(v): (v - ((v >> 1) & 0x77777777) - ((v >> 2) & 0x33333333) - ((v >> 3) & 0x11111111))
    #def bc(v): ((bx(v) + (bx(v) >> 4)) & 0x0F0F0F0F) % 255

    v = (v - ((v >> 1) & 0x77777777) - ((v >> 2) & 0x33333333) - ((v >> 3) & 0x11111111))
    v = ((v + (v >> 4)) & 0x0F0F0F0F)
    return v % 255



#http://mail.python.org/pipermail/python-list/1999-July/007696.html
import marshal, array, struct, string
POPCOUNT8_TRANS_TABLE = "".join(map(chr, POPCOUNT_TABLE8))

#changed by me to match new dumps() and use sum()
def popcount_timpeters(v):
    counts = array.array("B", string.translate(marshal.dumps(v), POPCOUNT8_TRANS_TABLE))
    # overwrite type code
    counts[0] = 0
    return sum(counts)

#changed by me to add loop unrolling and not setting digitcounts[0]
def popcount32_timpeters2(v):
    counts = array.array("B", string.translate(marshal.dumps(v), POPCOUNT8_TRANS_TABLE))
    return counts[1] + counts[2] + counts[3] + counts[4]

#improved by me: no need to translate type char
def popcount32_timpeters3(v):
    dumped = marshal.dumps(v)
    return POPCOUNT_TABLE8[ord(dumped[1])] + POPCOUNT_TABLE8[ord(dumped[2])] + POPCOUNT_TABLE8[ord(dumped[3])] + POPCOUNT_TABLE8[ord(dumped[4])]

#http://mail.python.org/pipermail/python-list/1999-July/007696.html
_run2mask = {1: 0x5555555555555555L,
             2: 0x3333333333333333L,
             4: 0x0F0F0F0F0F0F0F0FL,
             8: 0x00FF00FF00FF00FFL}

def buildmask2(run, n):
    run2 = run + run
    k = (n + run2 - 1) / run2
    n = k * run2
    try:
        answer = _run2mask[run]
        k2 = 64 / run2
    except KeyError:
        answer = (1L << run) - 1
        k2 = 1
    while k > k2:
        k2 = k2 + k2
        if k >= k2:
            answer = answer | (answer << (run * k2))
        else:
            answer = answer | (answer << (run2 * (k - k2/2)))
            k2 = k
    if k2 > k:
        answer = answer >> (run2 * (k2 - k))
    return answer, n

def nbits(v):
    return 32 #???

def popcount_seistrup(v):
    lomask, n = buildmask2(1, nbits(v))
    v = v - ((v >> 1) & lomask)
    target = 2
    while n > target:
        lomask, n = buildmask2(target, n)
        v = (v & lomask) + ((v >> target) & lomask)
        target = target + target
        for i in range(1, target/2):
            if n <= target:
                break
            n = n >> 1
            n = (n + target - 1) / target * target
            v = (v & ((1L <<>> n)
    return int(v)
   

if __name__ == "__main__":
    import time, random

    def time_func(func):
        before = time.time()
        result = func()
        after  = time.time()
        span   = after - before
        return result, span

    popcounts = [popcount_naive,       
                 popcount32_table8,    
                 popcount32_table16,   
                 popcount_table16_kernighan,
                 popcount_kernighan,   
                 popcount32_ops64,     
                 popcount32_parallel,  
                 popcount32_bagwell,   
                 popcount_elklund,     
                 popcount32_freebsd,   
                 popcount32_bsdmacro,  
                 popcount_seistrup,    
                 popcount_timpeters,   
                 popcount32_timpeters2,
                 popcount32_timpeters3,
                 ]

    test_count      = 30000
    max_int         = 2**31 - 2
    ints            = range(0, 257) + [random.randint(0, max_int) for _ in xrange(test_count)] + range(max_int - 100, max_int+1)
    expected_counts = map(popcount_naive, ints)
    for popcount in popcounts:
        counts, timespan = time_func(lambda : map(popcount, ints))
        print "%5.5f %s" % ((timespan if (counts == expected_counts) else -1), popcount.__name__) #-1 means failure

76 comments:

  1. In python 3 I've found (to my disappointment) that a simple bin(num).count('1') is faster than the table16 algorithm you've posted. As I was trying to replace the gmpy version of popcount I was using, this was not good enough. Thankfully, I was interested in a special case of the problem, namely I was doing a test for

    popcount(a) > 1

    so, inspired by the posted algorithm, I was able to replace that with:

    a not in onebit

    where onebit is a tuple constructed as follows:

    onebit = [0]
    for i in range(32): onebit.append(2**i)
    onebit = tuple(onebit)

    another benefit is that you get to set the size you are interested in just by changing the range of the loop. (in my case, 17 was sufficient.

    ReplyDelete
  2. Interesting results, thanks for compiling this.

    One option that has been over-looked, perhaps, is an 11-bit look-up table:

    POPCOUNT_TABLE11 = [0] * (1 << 11)
    for index in xrange(len(POPCOUNT_TABLE11)):
        POPCOUNT_TABLE11[index] = (index & 1) + POPCOUNT_TABLE11[index >> 1]

    def popcount32_table11(v):
        return (POPCOUNT_TABLE11[ v        & 0x7ff] +
                POPCOUNT_TABLE11[(v >> 11) & 0x7ff] +
                POPCOUNT_TABLE11[ v >> 22         ])


    This actually runs the fastest on my system, I imagine due to caching better than the 16-bit table, being 32x smaller.

    ReplyDelete
  3. The problem is that your benchmarks assume your aren't doing anything OTHER than popcount. On newer x86 processors, the 64K table will fit in (and fill) the L1 data cache, making it very fast, but only as long as it can hog the entire L1 cache! In real code, you'll likely be doing other things that require L1 cache as well, so this will run effectively 3x slower (L2 cache speed)...

    ReplyDelete
  4. خدمات النظافة بالدمام لابد ان تقدمها شركة لديها ثقة في اتمام خدمات النظافة المنزلية لان النظافة العاية لا تعطي النتيجة الفعالة التي تتم بواسطة شركة تنظيف بالدمام متخصصة لانها تهتم بكل شئ داخل المباني فلدينا شركة تنظيف فلل بالدمام تكون متخصصة في نظافة الفلل المفروشة والمستعملة واعطائها الرونق الجمالي الخاص بها لدينا شركة تنظيف شقق بالدمام متخصصة في اعمال نظافة الشقق المنزلية وشقق المكاتب والمعارض بواسطة الادوات والمواد اللازمة لعمل ذلك لدينا تخصصتنا في اعمالنا التي ترضي العميل وتخلصة من الحشرات الصغيرة التي تسبب ازعاج كبير للاسرة من خلال شركة مكافحة حشرات بالدمام التي لديها معدتها وموادها لعمل ذلك كما يوجد متخصص ايضا للقضاء علي الحشرات من خلال التواصل مع شركة رش مبيدات بالدمام التي تنتهيك من كل الحشرات المنزلية كما نعمل معا للواصل اليك كل الخدمات المنزلية من خلال خدمة الاثاث بواسطة افضل شركة نقل اثاث بالدمام والتعامل معها سوف يصل الي منزلك الجيد بدون اي تعب
    كما يوجد خدمتنا الاخري التي يمكنك البحث عنها م والاستفادة منها
    شركة تنظيف بالقطيف
    شركة تنظيف بالجبيل
    شركة تنظيف بالاحساء

    ReplyDelete
  5. I am read your article and it’s helped me a lot, thank you so much for share this wonderful article, I really like to read this type of blog, keep sharing this type of useful information, I am suggest to my all contact to visit this blog and collect this helpful information, If any one searching website designing & development company in Delhi please visit my website, we are do for you any think like website build PPC service and many more so don’t waste your time and come on my website and grow more your business, Thank you so much for read my comment. Ecommerce Website Designing Company in Delhii

    ReplyDelete
  6. This was be great I will read your blog properly, thank you so much for share this valuable information, I am enjoy to read this, it’s provided me lot of information, if any one grow up looking so please visit me website and I am share for you some tips so you will go and grow up your looks, thank you so much for read my comment.
    Lifestyle Magazine India

    ReplyDelete

  7. عالميه الدمام- 0542613483 - افضل شركات نقل العفش بالمنطقه الشرقيه شركة نقل عفش بالجبيل
    هل تبحث عن شركة مناسبة للقيام بنقل عفش منزلك، هل تخشى من تجارب الأصدقاء المؤلمة مع شركات نقل العفش؟ شركة نقل عفش بالقطيف
    لا تقلق عزيزي العميل، فأنت الآن في المكان الصحيح، حيث جاءت إليك شركة نقل عفش بالدمام شركة نقل اثاث بالخبر

    ReplyDelete
  8. يمكن تعريف الشحن المحدود الذي تقدمه شركه نقل اثاث بالدمام بكونه ما يقتصر على نقل ما قد يحتاجه العميل من أثاث كالأجهزة الكهربائية أو الأثاث الخشبية حتى وإن كان لقطع غيرة ومدودة منه. شركة نقل عفش بالخبر
    نقل عفش بالخبر
    شركة نقل عفش فى بالخبر
    وجدير بالذكر أنه بعد الرفع يقوم العمال بتركيب الأثاث كما كان شركات نقل العفش بالخبر

    ReplyDelete
  9. شركتنا شركة نقل اثاث بالجبيل الأفضل كونها تنظم من عملها، وتنظم من عمالتها، فكل عامل له عمل مخصص يقوم به. نقل عفش بالدمام
    نقل اثاث بالدمام
    نقل عفش بالاحساء
    لن تجد أجدر من شركه نقل عفش بالدمام قادرة على إتمام تلك المهمة حيث ثقة عملائها الكرام على المحك ولن تقبل تحت أي حال من الأحوال أن يخيب ظن العملاء نقل اثاث بالاحساء

    ReplyDelete
  10. شركة نقل عفش بالدمام
    عالميه الدمام- 0542613483 - افضل شركات نقل العفش بالمنطقه الشرقيه شركة نقل اثاث بالدمام
    ارخص شركة نقل اثاث بالدمام
    شركة نقل اثاث بالجبيل
    أن الشركة تتمتع بالالتزام التام بمواعيدها، فلا تعمل على مخالفتها تحت أي ظرف من الظروف وهذا بداية من عملية الاتصال وحتى إنهاء الخدمة تمامًا، كما أن فريق العمل ذو حجم كبير نسبيًا نقل عفش بالخبر
    شركة نقل عفش بالجبيل
    شركة نقل عفش بالجبيل

    ReplyDelete
  11. انوار طيبة أفضل شركة نظافة بالدمام متخصصة في مجال التنظيف بالدمام والمناطق المجاورة فنحن شركة تنظيف مكيفات بالدمام نقوم أيضاً بتنظيف (فلل– شقق- منازل- بيوت- المجالس- العمائر- الشركات – المطاعم – الفنادق- المحال التجارية) وجميع الأماكن التي تحتاج للتنظيف، وتقوم الشركة بتنظيف منزلك بأحدث الماكينات شركة تنظيف مكيفات بالدمام
    شركة تنظيف مكيفات بالخبر
    شركة تنظيف بالخبر تقدم أسعار مميزة لعملائها فهي أرخص شركة تنظيف مكيفات حيث تقوم بتنظيف المنازل والشقق والفلل والكنب والسجاد والمسابح والمدارس والمساجد والخزانات بالدمام و بالخبر و بالجبيل و بالقطيف تستخدم أجود أنواع المنظفات فهي افضل شركة نظافة بالخبر شركة غسيل مكيفات بالدمام
    شركة تنظيف مكيفات بالقطيف
    مؤسسة انوار طيبة-ارخص شركة تنظيف مكيفات بالقطيف والدمام والجبيل – افضل شركة تنظيف مكيفات السبلت بالدمام والقطيف، وتنظيف وصيانة وغسيل المكيفات سبليت ومركزية ومخفي وكاست ودولابي وشباك وتركيب جميع المكيفات شركتنا افضل شركة غسيل مكيفات بالدمام والجبيل تتعامل معكم شركة تنظيف مكيفات برأس تنورة

    ReplyDelete
  12. شركة تنظيف كنب بالدمام عندما تريد نظافه الكنب الموجود بمنزلك لاتنزعج اليك أفضل شركه تنظيف مكيفات بالدمام باحدث المكينات وافضل طرق التنظيف افضل شركة تنظيف كنب بالدمام نحن بعون الله من اكبر شركات التنظيف الكنب والمجالس بالدمام والخبر والقطيف والجبيل متخصصون فى مجال تنظيف جميع الاقمشه من ستائر ومجالس شركة تنظيف كنب بالدمام
    شركة غسيل كنب بالدمام
    افضل شركة تنظيف بالدمام و بالخبر ارخص الاسعار ، لنظافة المنازل و الشقق اهمية كبيرة في صحة الاسرة ، ولذلك اخترنا في الوطنية للنظافة بالمنطقة الشرقية افضل شركة تنظيف بالدمام و بالخبر ان نقدم لاهل الدمام والخبر خدمات تنظيف شاملة مع التعقيم لكافة مكونات المنزل العصري من اثاث او مفروشات او حمامات و مطابخ وتنظيف سيراميك وجلى بلاط شركة تنظيف كنب بالقطيف

    ReplyDelete
  13. شركة مكافحة حشرات بالخبر تقدم لكم العديد من الخدمات المميزة، حيث أن الشركة تستطيع مكافحة النمل الابيض بالقطيف بالإضافة إلى كافة أنواع الحشرات الأخرى بكل سهولة وبأحدث الإمكانيات مثل مكافحة البق بالقطيف ومكافحة الصراصير بالقطيف ومكافحة الصراصير بالقطيف ولها فروع مثل شركة مكافحة حشرات بالدمام شركة مكافحة حشرات بالقطيف
    شركة مكافحة حشرات بالدمام. ان شركة مكافحة حشرات بالدمام تعلم جيدا ان الحشرات من أكثر الكائنات الحية انتشارا وتواجد على سطح الأرض حيث انها تعيش وتتكيف في المناخات المختلفة وتعرف شركة رش مبيدات بالدمام ان بعض الحشرات يعيش في جميع الاماكن فبعض الحشرات تستطيع الطيران فذلك يجعلها تنجو ولكن تفضي عليها من خلال افضل شركة مكافحة حشرات بالمنطقة الشرقية ، شركة الشرق الاوسط للنظافة ومكافحة الحشرات شركة مكافحة حشرات بالخبر
    شركة مكافحة حشرات بالدمام
    شركة مكافحة حشرات برأس تنورة

    ReplyDelete
  14. ان حشرة البق تشكل خطورة كبيرة علي المنازل وحصوصا الاطفال لذلك يمكنك ايجاد الحل الامثل من خلال شركة مكافحة البق بالدمام حيث تضم الشركة افضل الخبراء فهي افضل شركة مكافحة البق بالدمام شركة مكافحة البق بالدمام
    شركة مكافحة البق بالخبر
    شركة مكافحة النمل الابيض بالدمام
    افضل شركة مكافحة النمل الابيض بالقطيف شركة  انوار طيبة ونصلك اينما كنت نستخدم افضل المبيدات للقضاء علي الحشرات النمل والصراصير وبق الفراش والوزع والنمل الابيض وجميع الحشرات الزاحفة ,مكافحة جميع انواع الحشرات باستخدام افضل المبيدات المستوردة والمحلية لضمان القضاء علي الحشرات مع الضمان وخصومات هائلة شركة مكافحة النمل الابيض بالقطيف
    شركات مكافحة حشرات ورش مبيدات بالدمام هل تبحث عن شركة مكافحة حشرات بالسعودية هل لديك نمل في المطبخ او حشرة البق في الخشب؟ هل عندك صراصير او نمل او فئران وتفسد عليك حياتك في منزلك او شركتك؟ لا تقلق فهناك العديد من شركات مكافحة الحشرات في السعودية وأيضا يوجد العديد من شركة رش مبيدات ومكافحة الحشرات بالدمام شركة رش مبيدات بالدمام

    ReplyDelete
  15. قبطان الخليج -0504353061-يُعد الأثاث من أكثر الأشياء التي تحتاج إلى حرص ودقة بالغة عند القيام بنقلها شركة نقل عفش بالظهران
    تحرص على تقديم الضمان اللازم عن العمل الذي تقوم به لعملائها الكرام، فالضمان بدوره يطمئن العميل وفي النفس الوقت يضمن مصداقية الشركة شركة نقل اثاث بالظهران

    ReplyDelete
  16. شركة نقل اثاث بالخبر
    دور شركة نقل أثاث بالقطيف في عملية نقل العفش شركة نقل عفش بالخبر
    شركة نقل اثاث بالقطيف
    أن العشوائية والعمل بدون تخطيط ووعي يكون مصيرهُ النهائي الفشل التام لا محالة من ذلك، لذلك فقد عمدت شركة نقل عفش بالخبر على أن تعمل وفقًا لاستراتيجية مُحددة شركة نقل عفش بالقطيف
    شركة نقل اثاث برأس تنورة

    ReplyDelete
  17. يمكن تعريف الشحن المحدود الذي تقدمه شركه نقل اثاث بالدمام بكونه ما يقتصر على نقل ما قد يحتاجه العميل من أثاث كالأجهزة الكهربائية أو الأثاث الخشبية حتى وإن كان لقطع غيرة ومدودة منه. شركة نقل عفش بالدمام
    شركة نقل اثاث بالدمام
    فريق عمل شركة نقل عفش بالدمام نعرف جميعًا أن موظفي وعُمال الشركة هم الأيد المُحركة لها، والتي تلعب الدور الأكبر في مدى نجاحها واستمراره أرخص شركة نقل عفش بالدمام

    ReplyDelete
  18. ان حشرة البق تشكل خطورة كبيرة علي المنازل وحصوصا الاطفال لذلك يمكنك ايجاد الحل الامثل من خلال شركة مكافحة البق بالدمام حيث تضم الشركة افضل الخبراء فهي افضل شركة مكافحة البق بالدمام شركة رش حشرات بالدمام
    شركة مكافحة حشرات بالدمام
    شركة مكافحة حشرات بالخبر تقدم لكم العديد من الخدمات المميزة، حيث أن الشركة تستطيع مكافحة النمل الابيض بالقطيف بالإضافة إلى كافة أنواع الحشرات الأخرى بكل سهولة وبأحدث الإمكانيات مثل مكافحة البق بالقطيف ومكافحة الصراصير بالقطيف ومكافحة الصراصير بالقطيف ولها فروع مثل شركة مكافحة حشرات بالدمام شركة مكافحة حشرات بالخبر
    شركة مكافحة البق بالدمام

    ReplyDelete
  19. شركة عزل اسطح بالدمام
    عزيزي العميل نرحب بكم في شركة كشف تسربات المياه بالجبيل هل تعاني من إرتفاع ... شركة كشف تسربات المياه بالخبر شركه تسربات  شركة كشف تسربات المياه بالجبيل
    شركة كشف تسربات المياه بالخبر
    هل تعبت عن البحث على شركة كشف تسربات المياه بالجبيل انتا الان مع شركة الافضل ... شركة كشف تسربات المياه بالدمام هى واحده من افضل الشركات شركة كشف تسربات المياه بالدمام

    ReplyDelete
  20. شركة تنظيف خزانات بالدمام
    التطور المستمر للشركة سواء من الناحية التكنولوجية أو الميدانية فكلاً منهما يعطي فائدة كبرى للأخرى، حيث تجد أن التكنولوجيا الحديثة التي تستخدمها شركة تنظيف خزانات بالدمام بالمعدات والأجهزة سهلت الأمر كثيراً في ميدان العمل عند تنظيف الخزانات شركة عزل خزانات بالدمام
    شركة تنظيف خزانات بالخبر
    مراعاة الشركة للمعايير والمقاييس الخاص بالسلامة لإعطاء أفضل النتائج، وما كان لنا سوى أن نهتم بذكر تلك النقاط عن كيفية عمل شركة غسيل خزانات بالقطيف شركة تنظيف خزانات بالقطيف

    ReplyDelete
  21. Thank you so much for this excellent Post and all the best for your future. I hope you and we will be sharing more thoughts and keep writing more like this one.

    office.com/setup
    mcafee.com/activate

    ReplyDelete
  22. I read your article it is very interesting and every concept is very clear, thank you so much for sharing. AWS Certification Course in Chennai

    ReplyDelete
  23. I need to thank you for this very good read and i have bookmarked to check out new things from your post. Thank you very much for sharing such a useful article and will definitely saved and revisit your site.
    Data Science Course

    ReplyDelete
  24. Excellent Blog! I would like to thank you for the efforts you have made in writing this post. Gained lots of knowledge.
    Data Analytics Course

    ReplyDelete
  25. Your site is truly cool and this is an extraordinary moving article and If it's not too much trouble share more like that. Thank You..
    Digital Marketing Course in Hyderabad

    ReplyDelete
  26. I am sure it will help many people. Keep up the good work. It's very compelling and I enjoyed browsing the entire blog.
    Business Analytics Course in Bangalore

    ReplyDelete
  27. Thank a lot. You have done excellent job. I enjoyed your blog . Nice efforts
    Data Science Certification in Hyderabad

    ReplyDelete
  28. What an incredible message this is. Truly one of the best posts I have ever seen in my life. Wow, keep it up.
    AI Courses in Bangalore

    ReplyDelete
  29. Wow, happy to see this awesome post. I hope this think help any newbie for their awesome work and by the way thanks for share this awesomeness, i thought this was a pretty interesting read when it comes to this topic. Thank you..
    Artificial Intelligence Course

    ReplyDelete
  30. Awesome article. I enjoyed reading your articles. this can be really a good scan for me. wanting forward to reading new articles. maintain the nice work!
    Data Science Courses in Bangalore

    ReplyDelete
  31. I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
    Data Science Training in Chennai

    ReplyDelete
  32. Thanks for sharing this informative content.,
    Leanpitch provides online training in Scrum Master Certification during this lockdown period everyone can use it wisely.
    Join Leanpitch 2 Days CSM Certification Workshop in different cities.

    Scrum master certification online

    CSM certification online

    ReplyDelete
  33. Thanks for sharing this informative content.,
    Leanpitch provides online training in Scrum Master Certification during this lockdown period everyone can use it wisely.
    Join Leanpitch 2 Days CSM Certification Workshop in different cities.
    CSM online

    CSM online certification

    ReplyDelete
  34. Thanks for sharing this informative content.,
    Leanpitch provides online training in Scrum Master Certification during this lockdown period everyone can use it wisely.
    Join Leanpitch 2 Days CSM Certification Workshop in different cities.
    CSM online training

    CSM training online

    ReplyDelete

  35. Thanks for sharing this informative content.,
    Leanpitch provides online training in Scrum Master Certification during this lockdown period everyone can use it wisely.
    Join Leanpitch 2 Days CSM Certification Workshop in different cities.
    CSM training online

    Scrum master training online

    ReplyDelete
  36. Thanks for sharing this.,
    Leanpitch provides online training in Scrum Master during this lockdown period everyone can use it wisely.
    Join Leanpitch 2 Days CSM Certification Workshop in different cities.

    Scrum master certification

    csm certification

    certified scrum master certification

    certified scrum master

    agile scrum master certification

    scrum master certification cost

    csm certification cost

    Scrum master Training

    Scrum master

    Best Scrum master certification

    ReplyDelete
  37. You have completed certain reliable points there. I did some research on the subject and found that almost everyone will agree with your blog.

    Data Science Training in Bangalore

    ReplyDelete
  38. Wonderful blog found to be very impressive to come across such an awesome blog. I should really appreciate the blogger for the efforts they have put in to develop such amazing content for all the curious readers who are very keen on being updated across every corner. Ultimately, this is an awesome experience for the readers. Anyways, thanks a lot and keep sharing the content in the future too.

    Digital Marketing Training in Bangalore

    ReplyDelete
  39. I found Habit to be a transparent site, a social hub that is a conglomerate of buyers and sellers willing to offer digital advice online at a decent cost.

    Artificial Intelligence Training in Bangalore

    ReplyDelete
  40. You actually make it seem like it's really easy with your acting, but I think it's something I think I would never understand. I find that too complicated and extremely broad. I look forward to your next message. I'll try to figure it out!

    Machine Learning Course in Bangalore

    ReplyDelete
  41. Very informative post and really appreciable. Keep doing great work like this.

    My web site - 부산오피

    (freaky)

    ReplyDelete
  42. I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
    aws training in hyderabad

    ReplyDelete
  43. I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
    business analytics courses

    ReplyDelete
  44. This is the most impressive article, thanks for sharing this information with us. Awesome work, I appreciate your work.
    Ac repair service in chennai Great story….Keep on sharing… Thanks

    ReplyDelete
  45. You provide such a wonderful article, the way of expressing the word is excellent. Fix the Common Verizon Email Problem like Change Verizon Password, Verizon email is not Working, Forgot Verizon Password etc.

    ReplyDelete
  46. I feel very grateful that I read this. It is very helpful and very informative and I really learned a lot from it.
    Data Analytics Course

    ReplyDelete
  47. I am sure it will help many people. Keep up the good work. It's very compelling and I enjoyed browsing the entire blog.
    Business Analytics Course in Bangalore

    ReplyDelete
  48. What an incredible message this is. Truly one of the best posts I have ever seen in my life. Wow, keep it up.
    AI Courses in Bangalore

    ReplyDelete
  49. I am really enjoying reading your well written articles. I am looking forward to reading new articles. Keep up the good work.
    Data Science Courses in Bangalore

    ReplyDelete
  50. I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
    Data Scientist Course in Delhi

    ReplyDelete
  51. This is the most impressive article, thanks for sharing this information with us. Awesome work, I appreciate your work.

    plots for sale in hyderabad
    property in secunderabad
    property in amaravathi
    property in vijayawada
    healing arena

    ReplyDelete
  52. After I originally left a comment I appear to have clicked on the -Notify me when new comments are added- checkbox and from now on every time a comment is added I receive 4 emails with the exact same comment. Perhaps there is an easy method you are able to remove me from that service? Thank you!

    대딸방

    ReplyDelete
  53. Thanks , I have just been looking for information approximately this subject for a while and yours is the greatest I've found out till now. However, what concerning the conclusion? Are you sure about the source?

    타이마사지

    ReplyDelete
  54. Pretty section of content. I just stumbled upon your web blog and in accession capital to assert that I get actually enjoyed account your blog posts. Any way I will be subscribing to your feeds and even I achievement you access consistently quickly.

    안마

    ReplyDelete
  55. I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
    Data Science Course in Gurgaon

    ReplyDelete

Blog Archive

Google Analytics