TA Performance Issue - Looking for OptionsSolved

Hi Wyatt,

Sorry for the long post...

I have a user who is having a performance issue with TurboActivate in my Windows program. I am using TA 4.3.0.0, which I know isn't the latest but in reviewing the changelog I didn't see anything new that seemed relevant to the performance issue.

Here's some background.

My Windows app (named CMC) is a multi-media application, similar to Windows Media Center. It is primarily used by movie/TV enthusiasts who have extremely large video collections (for example, I have over 60TB of movies, and my collection is on the small side compared to many of my users). Of course, to store a collection this large, you need a LOT of HDD space.

Most of my users have NAS servers to store their collections, but I do have a few users who have local storage, HDD's on the same PC on which they run CMC.

One user in particular has 26 external USB HDD's, plus more internal drives. Yes, twenty-six!

You and I actually chatted regarding this exact user before about 18 months ago (though at the time I hadn't pinpointed the USB drives as the issue): https://wyday.com/forum/t/4325/slow-isgenuine-check-after-reboot-on-some-pcs/

Back then, the performance issue was more of an inconvenience, as he was seeing 15 second startup times after a reboot.

These days the issue has become much worse. It's not just a reboot that will cause the longer TA processing time, but even just letting the PC be idle for over an hour will do it (perhaps some external drives are sleeping after this time and exacerbating the problem).

And instead of 15 second delays, they are well over a minute. This morning we clocked one at 82 seconds just for a call to TA.GenuineDays. Here is the code that caused the 82 second delay:

TA := TurboActivate.Create('secret-guid');GenuineDaysLeft := TA.GenuineDays(90,14, inGrace); //82 seconds to return

I understand that this increased processing time is directly related to this user's external drives. But I can't ask this user to unplug these drives when using CMC, because that's where all the movie data lives that CMC needs.

So I'm a bit caught between a rock and a hard place, and I'm asking for your help on some kind of creative solution. Is there something I can do to alleviate this user's pain?

Is there a different order of calls I can make to minimize how often TA needs to fingerprint the hardware (or whatever step it is that is so slow)? Or maybe there are some function parameters I can set to change the behavior?

Or maybe I can make the calls to TA conditional based upon the # of GenuineDays left. After all, I set the DaysBetweenChecks to 90 days, so once the license is valid I guess I'm okay with not fingerprinting for 90 days. That is the approach I was chasing in my above code, hoping that GenuineDays would be quicker than IsGenuine, but the response time wasn't any quicker like I hoped.

Currently it seems that TA fingerprinting is happening every time CMC runs, and if it's been longer than an hour since the last time then it's taking a really long time.

I appreciate any help you can provide.

Paul

, edited

Hey Paul,

The solution is to put the TA_IsGenuineEx() function call in a separate thread. And while you wait for the result from that separate thread, do any other work you need to do as part of the startup.

Thanks for the answer Wyatt. Unfortunately, that is not the solution for my app. I left out a detail that I thought was irrelevant, but now I see I should have mentioned this.

CMC is heavily threaded. I kick off threads left and right to perform tasks without bottlenecking. This includes activation checks, as long ago I put all of the TA tasks into a separate thread.

The problem is related to how I sell my software. Unlicensed versions are considered "Free", and are fully functional except that they are limited to 101 movie titles. Buying a license removes that 101 title restriction. I don't do Trials. Free with up to 101 titles, or paid.

During startup, CMC loads the movie DB in a separate thread, which then pauses waiting on the TA activation check results. AT that point, the DB may have contained thousands of movies, so the startup holds here and doesn't display anything in case the license is not valid. If TA comes back that the app is unlicensed, then the DB loaded modifies the loaded DB, truncating it to 101 titles, and proceeds to show the loaded data. If TA comes back that the app is licensed, then the DB is shown as is, with all titles.

CMC is a very fast app, and with the benefit of all those threads, the startup takes only 2-3 seconds even for very large collections, and the TA thread typically finishes in < 1 second so there is no performance penalty to this design.

But because TA thread is taking 80+ seconds for this user, the DB load thread is paused, waiting on the TA results to determine whether to apply the free version title limit, and the whole app is then waiting on the DB load thread to complete.

I know that this is not a typical design, but CMC is a very unique app.

I mean the actual solution: don't connect 26 platter-harddrives to a USB hub.

TurboActivate also tries to go as fast as possible. But... if a customer makes a very unusual decision, then TA will have to work around those decisions (which might involve powering up, spinning up each harddrive, and querying the results).

Solution? Don't do that.

A little bit of inside baseball: we do audit how we query components from time-to-time to make sure we're using the most efficient method. And how we query hard-drives has gotten a lot of attention. In particular because from time to time end-users use cheap-chinese-garbage SD cards (that malfunction in the best of circumstance), or a billion cheap-spinning-platter connected through a USB hub using some off-brand USB controller (and all other manner of craziness) and we want to handle these use-cases as quickly as possible.

And we are. Currently, with TA 4.3.2.x, we're going as fast as we can when querying hardware. The problem is that the customer has a very unusual setup with cheap hardware.

They can still use the cheap hardware, and fix their setup. But my guess is that they won't do that. The type of people that do crazy things like that tend to be pretty stubborn and pretty noisy.

What might help: don't set the harddrives to ever go to sleep. But that's a hack to fix a bad configuration to begin with.

Directly from the user: "The drives are powered continuously."

While I agree that connecting dozens of USB HDD's through USB hubs is not a great solution in general, it only seems to be causing a problem with TA. While I've been helping the user understand why TA takes so long with his setup, he's extremely frustrated that his very expensive hardware (likely $5k-$10k in PC + storage) somehow has performance issues, but only with TA, and that everything else runs blazing fast.

I have pointed out to him that the USB hubs could be the fly in the very expensive ointment, and I think he's considering trying some different hubs, but my hope is low that they will bring relief. After all, when buying USB hubs they list a lot of technical specs and features, but "Fast with TA fingerprinting" is never one of those specs, so how do you choose?

Unfortunately, I don't get to dictate my user's hardware. Regardless of how wise or ill-conceived any user's hardware choices, these abominations do exist. Telling a user they need to spend more than $3k to replace their current 100TB of storage with something TurboActivate compliant seems like poor customer relations. And I value every last one of my customers, and want to provide a good solution for them.

Back to why I came here for help: So if I can't change the customer's hardware, what are some creative options that I can do?

For example, what if I put in a hard-coded list of product keys in my app (starting with just his key), and do something different for these product keys? The idea floating around in my head is that perhaps I could only do the product IsGenuine check once every 90 days, but only for certain product keys.

The problem is that I don't know how to figure out where we are in the 90 day cycle without using GenuineDaysLeft, which seems to do the fingerprinting and have the same performance issues as IsGenuine. Is there a way for me to get that value without triggering a fingerprint?

I understand that TA is a black box by design, to protect your IP, and I fully support that. But since I can't see inside the box, I'm fumbling around looking for options, and guessing at what might work. I need your guidance on how I can retrieve some data from TA without triggering the fingerprinting on certain product keys. Something like a "DaysLeft()" function call that doesn't do the "Genuine" fingerprinting step.

If I had the Key and the Days Left, without triggering a fingerprint, I'd be all set. Or other creative options that I haven't thought about.

Paul

Paul

If youre asking what USB hub can I use for 26 hard drives youre asking too many wrong questions.

If you want to be fast even for insane setups, then process TA_IsGenuineEx() in the background and continue running your app as if its licensed. Then when that thread completes (or a timeout of 3 minutes or so) process the result and lock the user out immediately if a timeout happens or if theyre unlicensed.

I was not asking what USB hub to buy ("so how do you choose?" was a rhetorical question, sorry you thought I was dumb enough to ask). I was simply pointing out that trying to buy a "good for TurboActivate USB hub" is an impossible task, something we seem to agree upon.

And since I can't seriously ask a user to spend $3k-$5k on a NAS and storage (to fix TA performance issue with their current $,$$$ hardware that you flippantly dismiss as cheap junk without any real evaluation), that instead I need some creative coding solutions. And since TA is a black box that I can't see inside of to determine what functions trigger and what functions avoid the time consuming fingerprint, I turned to you for help on these creative coding solutions.

Your suggestion that I allow the user to run as if licensed for 3 minutes, then lock them out later, is a step in the right direction. I appreciate you trying to provide a workaround, but your suggestion falls short of working in the real world due to the unique requirements of my app.

Technically, what I am licensing is the # of records the user can have in CMC's movie database (which is just a small binary file, anywhere from a few MB for small collections to 100+ MB for large collections). I'm not restricting access to the app, I'm restricting access to more than 101 titles in their DB for unlicensed users.

I have many users with multiple licenses, because they have a lot of media center PC's and TV's in their house. I even have a few users with 8 or more licenses, which is amazing to me, but they really have that many PC's and TV's to watch their collection.

But what you propose would allow them to have 1 license to run CMC and create the DB, then write a little script and copy that relatively small DB file around to all their other PC's and make the DB file write protected. Then they can run CMC unlicensed, and get 3 minutes of free access to their movie collection. Since the DB is write protected, at most I could kick them out of CMC but I couldn't truncate the DB file, and worse they could start CMC right back up and continue where they left off.

This also opens up the door that users could enable this "free 3 minutes - continuously" mode by plugging a cheap Chinese junk USB hub into the PC. The anti-dongle!

Why is 3 free minutes a problem? CMC is amazingly lightweight and fast, so in 30 seconds you could easily start it up, navigate to a movie, and start playback. And because CMC offloads the playback to other programs, it doesn't matter if CMC locks them out after 3 minutes, because they already got what they wanted and are watching their movie.

That's why I have CMC pause after loading the DB, waiting on the TA result to see if the license is still good. That gives CMC the opportunity to truncate the unlicensed PC's movie DB in RAM before showing it, preventing users from loading and accessing a DB from a larger collection that was created by a licensed copy of CMC.

I've tried to guide you towards suggestions that will actually work for CMC. The current code works for > 99% of users, so I don't want to break it, and TA is working fantastic for them.

For this 1 user, I need some type of exception to get around his hardware constraint. Given that I know his PKey #, I thought I could trigger the exception logic only with his key, so as not to break the current logic that works for all other users.

Ideally, it would be great if I could limit the IsGenuine type fingerprinting for this 1 PKey to once every 90 days, instead of every time CMC runs. Since you avoiding discussing a solution to this when I asked earlier, your silence on this seems to suggest that this would be impossible?

I'm comfortable programming an exception for this user's PKey, but that does mean I need TA to return both the PKey and the DaysLeft values quickly (without triggering the fingerprint which causes delayed TA responses). That way I can selectively apply the exception only for this one PKey, and only when there are >0 days left.

That's the only idea I've been able to come up with, and I'm still hopeful you can either make it a reality, or provide other alternatives that similarly work with the unique needs of my app.

Well, TA_GetPKey() will not trigger the fingerprinting function. However getting the trial days remaining will. As will most other functions.

Answer

We've fixed this issued (many and/or very slow and/or broken "storage devices") in TA / TF / TFS 4.4, out now.