Monday, February 8, 2021

Digest for comp.lang.c++@googlegroups.com - 10 updates in 6 topics

Mike Garcia <mike@mgarcia.nospam>: Feb 08 10:53PM

Hi,
I'm looking for an old unix/win95'ish commandline executable.
 
"TGA2IMG takes an uncompressed 24-bit Targa file and converts it to a
format that was used by the Vivid raytracer."
 
It's an old program witch converted tga images to other formats, including
c code and header files (like bin2c), I can't seem to find the original
exe or code to it on github or SF or a web search.
 
 
Here's what the usage command looks like:
tga2img -q -r4 -i320,0 -p0,480 file.tga
 
 
 
I've found 2 different programs but it's not it:
 
 
VIVID2.ZIP from: http://files.mpoli.fi/software/DOS/GRAPHICS/
 
TGA2IMG Version 1.01
Converts 24 bit TGA files to 24 bit IMG(Vivid) files.
Copyright 1990, Dan Farmer
 
Usage: Z:\TGA2IMG.EXE File[.TGA]
 
 
 
and ... not sure what THUG2 or THPS4 is but that's not it also :/
 
http://www.thps-mods.com/forum/viewtopic.php?t=598
 
+ THUG2 TGA to IMG Converter v0.2 + by Yoshua (Defeat0r)
+ Web: http://jmn-web.tk ---------------------------------
For THUG2 or THPS4? 1/2
 
 
 
 
Anyone got a win32 exe or the source code to tga2img?
 
Cheers Mike.
 
 
 
 
--
 
Mike Garcia
http://mgarcia.org
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Feb 07 08:20PM -0800

Well, here is a test program. When you get some free time, can you
please try to run it; give it a go?
 
This is a crude implementation, but it shows how reader threads can
iterate a lockfree stack while writer threads are mutating it. 100%
lockfree. Before I post my output, I want to see yours. The output you
get should be identical to my output. Will be adding a lot more context
here sometime tomorrow. Looking forward to your input, and showing me
your output. If you find any issues, please, I am all ears, or eyes wrt
reading the posts... ;^)
 
Here is the code, it should compile right up with C++11. My next version
will use C++17 and alignas.
 
https://pastebin.com/raw/nPVYXbWM
_____________________________________
// Chris M. Thomassons Poor Mans RCU... Example 123...
 
 
#include <iostream>
#include <atomic>
#include <thread>
#include <cstdlib>
#include <cstdint>
#include <climits>
#include <functional>
 
 
// Masks
static constexpr std::uint32_t ct_ref_mask = 0xFFFFFFF0U;
static constexpr std::uint32_t ct_ref_complete = 0x30U;
static constexpr std::uint32_t ct_ref_inc = 0x20U;
static constexpr std::uint32_t ct_proxy_mask = 0xFU;
static constexpr std::uint32_t ct_proxy_quiescent = 0x10U;
 
 
// Iteration settings
static constexpr unsigned long ct_reader_iters_n = 1000000;
static constexpr unsigned long ct_writer_iters_n = 100000;
 
 
// Thread counts
static constexpr unsigned long ct_reader_threads_n = 42;
static constexpr unsigned long ct_writer_threads_n = 7;
 
 
// Some debug/sanity check things...
// Need to make this conditional in compilation with some macros...
static std::atomic<std::uint32_t> g_debug_node_allocations(0);
static std::atomic<std::uint32_t> g_debug_node_deallocations(0);
 
 
// Need to align and pad data structures! To do...
 
struct ct_node
{
std::atomic<ct_node*> m_next;
ct_node* m_defer_next;
 
ct_node() : m_next(nullptr), m_defer_next(nullptr)
{
g_debug_node_allocations.fetch_add(1, std::memory_order_relaxed);
}
 
~ct_node()
{
g_debug_node_deallocations.fetch_add(1, std::memory_order_relaxed);
}
};
 
 
// The proxy collector itself... :^)
template<std::size_t T_defer_limit>
class ct_proxy
{
static void prv_destroy(ct_node* n)
{
while (n)
{
ct_node* next = n->m_defer_next;
delete n;
n = next;
}
}
 
 
public:
class collector
{
friend class ct_proxy;
 
private:
std::atomic<ct_node*> m_defer;
std::atomic<std::uint32_t> m_defer_count;
std::atomic<std::uint32_t> m_count;
 
 
 
public:
collector()
: m_defer(nullptr),
m_defer_count(0),
m_count(0)
{
 
}
 
 
~collector()
{
prv_destroy(m_defer.load(std::memory_order_relaxed));
}
};
 
 
private:
std::atomic<std::uint32_t> m_current;
std::atomic<bool> m_quiesce;
ct_node* m_defer;
collector m_collectors[2];
 
 
public:
ct_proxy()
: m_current(0),
m_quiesce(false),
m_defer(nullptr)
{
 
}
 
~ct_proxy()
{
prv_destroy(m_defer);
}
 
 
private:
void prv_quiesce_begin()
{
// Try to begin the quiescence process.
if (! m_quiesce.exchange(true, std::memory_order_acquire))
{
// advance the current collector and grab the old one.
std::uint32_t old =
m_current.load(std::memory_order_relaxed) & ct_proxy_mask;
old = m_current.exchange((old + 1) & 1,
std::memory_order_acq_rel);
collector& c = m_collectors[old & ct_proxy_mask];
 
// decode reference count.
std::uint32_t refs = old & ct_ref_mask;
 
// increment and generate an odd reference count.
std::uint32_t old_refs = c.m_count.fetch_add(refs +
ct_proxy_quiescent, std::memory_order_release);
 
if (old_refs == refs)
{
// odd reference count and drop-to-zero condition detected!
prv_quiesce_complete(c);
}
}
}
 
 
void prv_quiesce_complete(collector& c)
{
// the collector `c' is now in a quiescent state! :^)
std::atomic_thread_fence(std::memory_order_acquire);
 
// maintain the back link and obtain "fresh" objects from
// this collection.
ct_node* n = m_defer;
m_defer = c.m_defer.load(std::memory_order_relaxed);
c.m_defer.store(0, std::memory_order_relaxed);
 
// reset the reference count.
c.m_count.store(0, std::memory_order_relaxed);
c.m_defer_count.store(0, std::memory_order_relaxed);
 
// release the quiesce lock.
m_quiesce.store(false, std::memory_order_release);
 
// destroy nodes.
prv_destroy(n);
}
 
 
public:
collector& acquire()
{
// increment the master count _and_ obtain current collector.
std::uint32_t current =
m_current.fetch_add(ct_ref_inc, std::memory_order_acquire);
 
// decode the collector index.
return m_collectors[current & ct_proxy_mask];
}
 
void release(collector& c)
{
// decrement the collector.
std::uint32_t count =
c.m_count.fetch_sub(ct_ref_inc, std::memory_order_release);
 
// check for the completion of the quiescence process.
if ((count & ct_ref_mask) == ct_ref_complete)
{
// odd reference count and drop-to-zero condition detected!
prv_quiesce_complete(c);
}
}
 
 
collector& sync(collector& c)
{
// check if the `c' is in the middle of a quiescence process.
if (c.m_count.load(std::memory_order_relaxed) & ct_proxy_quiescent)
{
// drop `c' and get the next collector.
release(c);
 
return acquire();
}
 
return c;
}
 
 
void collect()
{
prv_quiesce_begin();
}
 
 
void collect(collector& c, ct_node* n)
{
if (! n) return;
 
// link node into the defer list.
ct_node* prev = c.m_defer.exchange(n, std::memory_order_relaxed);
n->m_defer_next = prev;
 
// bump the defer count and begin quiescence process if over
// the limit.
std::uint32_t count =
c.m_defer_count.fetch_add(1, std::memory_order_relaxed) + 1;
 
if (count >= (T_defer_limit / 2))
{
prv_quiesce_begin();
}
}
};
 
 
 
typedef ct_proxy<10> ct_proxy_collector;
 
 
// you're basic lock-free stack...
// well, minus ABA counter and DWCAS of course! ;^)
class ct_stack
{
std::atomic<ct_node*> m_head;
 
 
public:
ct_stack() : m_head(nullptr)
{
 
}
 
 
public:
void push(ct_node* n)
{
ct_node* head = m_head.load(std::memory_order_relaxed);
 
do
{
n->m_next.store(head, std::memory_order_relaxed);
}
 
while (! m_head.compare_exchange_weak(
head,
n,
std::memory_order_release));
}
 
 
ct_node* flush()
{
return m_head.exchange(nullptr, std::memory_order_acquire);
}
 
 
ct_node* get_head()
{
return m_head.load(std::memory_order_acquire);
}
 
 
ct_node* pop()
{
ct_node* head = m_head.load(std::memory_order_acquire);
ct_node* xchg;
 
do
{
if (!head) return nullptr;
 
xchg = head->m_next.load(std::memory_order_relaxed);
}
 
while (! m_head.compare_exchange_weak(
head,
xchg,
std::memory_order_acquire));
 
return head;
}
};
 
 
// The shared state
struct ct_shared
{
ct_proxy<10> m_proxy_gc;
ct_stack m_stack;
};
 
 
 
// Reader threads
// Iterates through the lock free stack
void ct_thread_reader(ct_shared& shared)
{
// iterate the lockfree stack
for (unsigned long i = 0; i < ct_reader_iters_n; ++i)
{
ct_proxy_collector::collector& c = shared.m_proxy_gc.acquire();
 
ct_node* n = shared.m_stack.get_head();
 
while (n)
{
// need to add in some processing...
//std::this_thread::yield();
 
n = n->m_next.load(std::memory_order_relaxed);
}
 
shared.m_proxy_gc.release(c);
}
}
 
 
 
// Writer threads
// Mutates the lock free stack
void ct_thread_writer(ct_shared& shared)
{
for (unsigned long wloop = 0; wloop < 42; ++wloop)
{
for (unsigned long i = 0; i < ct_writer_iters_n; ++i)
{
shared.m_stack.push(new ct_node());
}
 
std::this_thread::yield();
 
ct_proxy_collector::collector& c = shared.m_proxy_gc.acquire();
 
for (unsigned long i = 0; i < ct_writer_iters_n; ++i)
{
shared.m_proxy_gc.collect(c, shared.m_stack.pop());
}
 
shared.m_proxy_gc.release(c);
 
std::this_thread::yield();
 
if ((wloop % 3) == 0)
{
shared.m_proxy_gc.collect();
}
}
}
 
 
 
int main()
{
std::cout << "Chris M. Thomassons Proxy Collector Port ver
.0.0.1...\n";
std::cout << "_______________________________________\n\n";
 
 
{
ct_shared shared;
 
std::thread readers[ct_reader_threads_n];
std::thread writers[ct_writer_threads_n];
 
std::cout << "Booting threads...\n";
 
for (unsigned long i = 0; i < ct_writer_threads_n; ++i)
{
writers[i] = std::thread(ct_thread_writer, std::ref(shared));
}
 
for (unsigned long i = 0; i < ct_reader_threads_n; ++i)
{
readers[i] = std::thread(ct_thread_reader, std::ref(shared));
}
 
std::cout << "Threads running...\n";
 
for (unsigned long i = 0; i < ct_reader_threads_n; ++i)
{
readers[i].join();
}
 
for (unsigned long i = 0; i < ct_writer_threads_n; ++i)
{
writers[i].join();
}
}
 
std::cout << "Threads completed!\n\n";
 
 
// Sanity check!
{
std::uint32_t node_allocations =
g_debug_node_allocations.load(std::memory_order_relaxed);
std::uint32_t node_deallocations =
g_debug_node_deallocations.load(std::memory_order_relaxed);
 
std::cout << "node_allocations = " << node_allocations << "\n";
std::cout << "node_deallocations = " << node_deallocations << "\n";
 
if (node_allocations != node_deallocations)
{
std::cout << "OH SHIT! NODE LEAK!!! SHIT! = " <<
node_allocations - node_deallocations << "\n\n";
}
 
}
 
std::cout << "\n\nTest Completed!\n\n";
 
return 0;
}
_____________________________________
 
Well, can you even get it compile on your end? What do you get?
 
Thanks everybody.
Manfred <noname@add.invalid>: Feb 08 01:50PM +0100

On 2/8/2021 5:20 AM, Chris M. Thomasson wrote:
> Well, here is a test program. When you get some free time, can you
> please try to run it; give it a go?
 
$ c++ --version
c++ (GCC) 10.2.1 20201125 (Red Hat 10.2.1-9)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
 
 
$ c++ -std=c++11 -Wall -O2 -lpthread rcu_chris.cc && ./a.out
Chris M. Thomassons Proxy Collector Port ver .0.0.1...
_______________________________________
 
Booting threads...
Threads running...
Threads completed!
 
node_allocations = 29400000
node_deallocations = 29400000
 
 
Test Completed!
Paavo Helde <myfirstname@osa.pri.ee>: Feb 08 09:14PM +0200

08.02.2021 06:20 Chris M. Thomasson kirjutas:
> here sometime tomorrow. Looking forward to your input, and showing me
> your output. If you find any issues, please, I am all ears, or eyes wrt
> reading the posts... ;^)
 
VS2017 x64 on Windows 10: no issues (8 physical cores)
 
Chris M. Thomassons Proxy Collector Port ver .0.0.1...
_______________________________________
 
Booting threads...
Threads running...
Threads completed!
 
node_allocations = 29400000
node_deallocations = 29400000
 
 
Test Completed!
 
-------------------------------------------------------------------------
 
gcc 7.4.0 on Linux: no issues (2 NUMA nodes, 24 physical cores)
 
Chris M. Thomassons Proxy Collector Port ver .0.0.1...
_______________________________________
 
Booting threads...
Threads running...
Threads completed!
 
node_allocations = 29400000
node_deallocations = 29400000
 
 
Test Completed!
Brian Wood <woodbrian77@gmail.com>: Feb 07 04:31PM -0800

On Sunday, February 7, 2021 at 2:04:38 PM UTC-6, Manfred wrote:
>

No comments: